summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c14
-rw-r--r--bgpd/bgp_attr.h14
-rw-r--r--bgpd/bgp_attr_evpn.c21
-rw-r--r--bgpd/bgp_attr_evpn.h8
-rw-r--r--bgpd/bgp_evpn.c52
-rw-r--r--bgpd/bgp_evpn_private.h2
-rw-r--r--bgpd/bgp_evpn_vty.c2
-rw-r--r--bgpd/bgp_packet.c8
-rw-r--r--bgpd/bgp_route.c11
-rw-r--r--bgpd/bgp_updgrp.c7
-rw-r--r--bgpd/bgp_vty.c85
-rw-r--r--bgpd/bgp_vty.h5
-rw-r--r--bgpd/bgp_zebra.c20
-rw-r--r--bgpd/bgpd.c37
-rw-r--r--bgpd/bgpd.h27
-rw-r--r--doc/user/bgp.rst6
-rw-r--r--isisd/isis_adjacency.c2
-rw-r--r--isisd/isis_lsp.c24
-rw-r--r--isisd/isis_nb_config.c7
-rw-r--r--isisd/isisd.c10
-rw-r--r--lib/frrcu.h2
-rw-r--r--lib/libospf.h1
-rw-r--r--lib/seqlock.c33
-rw-r--r--ospfd/ospf_flood.c26
-rw-r--r--ospfd/ospf_flood.h23
-rw-r--r--ospfd/ospf_interface.c44
-rw-r--r--ospfd/ospf_interface.h17
-rw-r--r--ospfd/ospf_ism.c14
-rw-r--r--ospfd/ospf_packet.c243
-rw-r--r--ospfd/ospf_packet.h5
-rw-r--r--sharpd/sharp_zebra.c2
-rw-r--r--tests/lib/test_atomlist.c18
-rw-r--r--tests/lib/test_seqlock.c5
-rw-r--r--tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py2
-rw-r--r--tests/topotests/bgp_oad/test_bgp_oad.py2
-rw-r--r--tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json2
-rw-r--r--tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json2
-rw-r--r--tests/topotests/bgp_remote_as_auto/__init__.py0
-rw-r--r--tests/topotests/bgp_remote_as_auto/r1/frr.conf23
-rw-r--r--tests/topotests/bgp_remote_as_auto/r2/frr.conf10
-rw-r--r--tests/topotests/bgp_remote_as_auto/r3/frr.conf10
-rw-r--r--tests/topotests/bgp_remote_as_auto/r4/frr.conf10
-rw-r--r--tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py161
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py3
-rw-r--r--tests/topotests/lib/common_check.py27
-rw-r--r--yang/frr-route-map.yang6
-rw-r--r--zebra/zebra_dplane.c4
-rw-r--r--zebra/zebra_rib.c3
48 files changed, 782 insertions, 278 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 18c7b13535..2ed49935e5 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2575,7 +2575,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- uint8_t sticky = 0;
bool proxy = false;
struct ecommunity *ecomm;
@@ -2605,21 +2604,20 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg);
/* Extract MAC mobility sequence number, if any. */
- attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
- attr->sticky = sticky;
+ attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr);
/* Check if this is a Gateway MAC-IP advertisement */
- attr->default_gw = bgp_attr_default_gw(attr);
+ bgp_attr_default_gw(attr);
/* Handle scenario where router flag ecommunity is not
* set but default gw ext community is present.
* Use default gateway, set and propogate R-bit.
*/
- if (attr->default_gw)
- attr->router_flag = 1;
+ if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW))
+ SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER);
/* Check EVPN Neighbor advertisement flags, R-bit */
- bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy);
+ bgp_attr_evpn_na_flag(attr, &proxy);
if (proxy)
attr->es_flags |= ATTR_ES_PROXY_ADVERT;
@@ -4468,6 +4466,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
bgp_packet_mpattr_end(s, mpattrlen_pos);
}
+ (void)peer_sort(peer);
+
/* Origin attribute. */
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ORIGIN);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index f353e76913..3519dc3401 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -197,9 +197,6 @@ struct attr {
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
- /* NA router flag (R-bit) support in EVPN */
- uint8_t router_flag;
-
/* Distance as applied by Route map */
uint8_t distance;
@@ -256,11 +253,12 @@ struct attr {
/* MP Nexthop length */
uint8_t mp_nexthop_len;
- /* Static MAC for EVPN */
- uint8_t sticky;
-
- /* Flag for default gateway extended community in EVPN */
- uint8_t default_gw;
+ /* EVPN flags */
+ uint8_t evpn_flags;
+#define ATTR_EVPN_FLAG_STICKY (1 << 0)
+#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1)
+/* NA router flag (R-bit) support in EVPN */
+#define ATTR_EVPN_FLAG_ROUTER (1 << 2)
/* route tag */
route_tag_t tag;
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index bbc4ba9525..086c36f36c 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -115,14 +115,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
/*
* return true if attr contains default gw extended community
*/
-uint8_t bgp_attr_default_gw(struct attr *attr)
+void bgp_attr_default_gw(struct attr *attr)
{
struct ecommunity *ecom;
uint32_t i;
ecom = bgp_attr_get_ecommunity(attr);
if (!ecom || !ecom->size)
- return 0;
+ return;
/* If there is a default gw extendd community return true otherwise
* return 0 */
@@ -136,10 +136,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
if ((type == ECOMMUNITY_ENCODE_OPAQUE
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
- return 1;
+ SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
}
-
- return 0;
+ UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
}
/*
@@ -183,7 +182,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
* Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0.
*/
-uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
+uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr)
{
struct ecommunity *ecom;
uint32_t i;
@@ -213,9 +212,9 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
flags = *pnt++;
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
- *sticky = 1;
+ SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
else
- *sticky = 0;
+ UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
pnt++;
pnt = ptr_get_be32(pnt, &seq_num);
@@ -229,8 +228,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
/*
* return true if attr contains router flag extended community
*/
-void bgp_attr_evpn_na_flag(struct attr *attr,
- uint8_t *router_flag, bool *proxy)
+void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy)
{
struct ecommunity *ecom;
uint32_t i;
@@ -254,7 +252,8 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
val = *pnt++;
if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
- *router_flag = 1;
+ SET_FLAG(attr->evpn_flags,
+ ATTR_EVPN_FLAG_ROUTER);
if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
*proxy = true;
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
index f8d3978b96..e12fc3a86c 100644
--- a/bgpd/bgp_attr_evpn.h
+++ b/bgpd/bgp_attr_evpn.h
@@ -36,12 +36,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr,
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst);
extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
-extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
- uint8_t *sticky);
-extern uint8_t bgp_attr_default_gw(struct attr *attr);
+extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr);
+extern void bgp_attr_default_gw(struct attr *attr);
-extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag,
- bool *proxy);
+extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy);
extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index e5c7cb3801..75a7d85e88 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -1159,7 +1159,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
}
/* Add MAC mobility (sticky) if needed. */
- if (attr->sticky) {
+ if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) {
seqnum = 0;
encode_mac_mobility_extcomm(1, seqnum, &eval_sticky);
ecom_sticky.size = 1;
@@ -1178,7 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
}
/* Add default gateway, if needed. */
- if (attr->default_gw) {
+ if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
encode_default_gw_extcomm(&eval_default_gw);
ecom_default_gw.size = 1;
ecom_default_gw.unit_size = ECOMMUNITY_SIZE;
@@ -1189,8 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
}
proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT);
- if (attr->router_flag || proxy) {
- encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy);
+ if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) {
+ encode_na_flag_extcomm(&eval_na,
+ CHECK_FLAG(attr->evpn_flags,
+ ATTR_EVPN_FLAG_ROUTER),
+ proxy);
ecom_na.size = 1;
ecom_na.unit_size = ECOMMUNITY_SIZE;
ecom_na.val = (uint8_t *)eval_na.val;
@@ -1275,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn
flags = 0;
if (pi->sub_type == BGP_ROUTE_IMPORTED) {
- if (pi->attr->sticky)
+ if (CHECK_FLAG(pi->attr->evpn_flags,
+ ATTR_EVPN_FLAG_STICKY))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (pi->attr->default_gw)
+ if (CHECK_FLAG(pi->attr->evpn_flags,
+ ATTR_EVPN_FLAG_DEFAULT_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
if (is_evpn_prefix_ipaddr_v6(p) &&
- pi->attr->router_flag)
+ CHECK_FLAG(pi->attr->evpn_flags,
+ ATTR_EVPN_FLAG_ROUTER))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
seq = mac_mobility_seqnum(pi->attr);
@@ -1834,7 +1840,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
*active_on_peer = true;
}
- if (second_best_path->attr->router_flag)
+ if (CHECK_FLAG(second_best_path->attr->evpn_flags,
+ ATTR_EVPN_FLAG_ROUTER))
*peer_router = true;
/* we use both proxy and non-proxy imports to
@@ -1934,7 +1941,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct attr local_attr;
struct bgp_labels bgp_labels = {};
int route_change = 1;
- uint8_t sticky = 0;
const struct prefix_evpn *evp;
*pi = NULL;
@@ -1966,9 +1972,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
local_attr = *attr;
/* Extract MAC mobility sequence number, if any. */
- local_attr.mm_seqnum =
- bgp_attr_mac_mobility_seqnum(&local_attr, &sticky);
- local_attr.sticky = sticky;
+ local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr);
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(&local_attr);
@@ -2063,9 +2067,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
BGP_PATH_ATTR_CHANGED);
/* Extract MAC mobility sequence number, if any. */
- local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(
- &local_attr, &sticky);
- local_attr.sticky = sticky;
+ local_attr.mm_seqnum =
+ bgp_attr_mac_mobility_seqnum(&local_attr);
attr_new = bgp_attr_intern(&local_attr);
@@ -2198,10 +2201,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
- attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0;
- attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
- attr.router_flag = CHECK_FLAG(flags,
- ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0;
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY))
+ SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY);
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
+ SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
+ SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
attr.es_flags |= ATTR_ES_PROXY_ADVERT;
@@ -2503,13 +2508,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
- attr.sticky = (local_pi->attr->sticky) ? 1 : 0;
- attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0;
+ attr.evpn_flags = local_pi->attr->evpn_flags;
attr.es_flags = local_pi->attr->es_flags;
- if (local_pi->attr->default_gw) {
- attr.default_gw = 1;
+ if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) {
+ SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
if (is_evpn_prefix_ipaddr_v6(&evp))
- attr.router_flag = 1;
+ SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
}
memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t));
bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr,
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 07bba9b426..b05df3d82a 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq,
}
static inline void encode_na_flag_extcomm(struct ecommunity_val *eval,
- uint8_t na_flag, bool proxy)
+ bool na_flag, bool proxy)
{
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 846a82ba90..c28cdb4a65 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -4840,7 +4840,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
char *vrf = NULL;
char *neighbor = NULL;
as_t as = 0; /* 0 means AS filter not set */
- int as_type = AS_UNSPECIFIED;
+ enum peer_asn_type as_type = AS_UNSPECIFIED;
uint16_t show_flags = 0;
if (argv_find(argv, argc, "vrf", &idx_vrf))
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9a047b9d45..4625f15778 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1977,6 +1977,14 @@ static int bgp_open_receive(struct peer_connection *connection,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as, 2);
return BGP_Stop;
+ } else if (peer->as_type == AS_AUTO) {
+ if (remote_as == peer->bgp->as) {
+ peer->as = peer->local_as;
+ SET_FLAG(peer->as_type, AS_INTERNAL);
+ } else {
+ peer->as = remote_as;
+ SET_FLAG(peer->as_type, AS_EXTERNAL);
+ }
} else if (peer->as_type == AS_INTERNAL) {
if (remote_as != peer->bgp->as) {
if (bgp_debug_neighbor_events(peer))
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 6a35935c7e..2a9fc6ce0d 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -851,8 +851,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
* with the
* sticky flag.
*/
- if (newattr->sticky != existattr->sticky) {
- if (newattr->sticky && !existattr->sticky) {
+ bool new_sticky = CHECK_FLAG(newattr->evpn_flags,
+ ATTR_EVPN_FLAG_STICKY);
+ bool exist_sticky = CHECK_FLAG(existattr->evpn_flags,
+ ATTR_EVPN_FLAG_STICKY);
+
+ if (new_sticky != exist_sticky) {
+ if (new_sticky && !exist_sticky) {
*reason = bgp_path_selection_evpn_sticky_mac;
if (debug)
zlog_debug(
@@ -861,7 +866,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
return 1;
}
- if (!newattr->sticky && existattr->sticky) {
+ if (!new_sticky && exist_sticky) {
*reason = bgp_path_selection_evpn_sticky_mac;
if (debug)
zlog_debug(
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 124e7a388b..b717793a45 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = 0;
- key = jhash_1word(peer->sort, key); /* EBGP or IBGP */
+ /* `remote-as auto` technically uses identical peer->sort.
+ * After OPEN message is parsed, this is updated accordingly, but
+ * we need to call the peer_sort() here also to properly create
+ * separate subgroups.
+ */
+ key = jhash_1word(peer_sort((struct peer *)peer), key);
key = jhash_1word(peer->sub_sort, key); /* OAD */
key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e9a79766ec..0ef1351835 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4862,7 +4862,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
as_t as;
- int as_type = AS_SPECIFIED;
+ enum peer_asn_type as_type = AS_SPECIFIED;
union sockunion su;
if (as_str[0] == 'i') {
@@ -4871,6 +4871,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
} else if (as_str[0] == 'e') {
as = 0;
as_type = AS_EXTERNAL;
+ } else if (as_str[0] == 'a') {
+ as = 0;
+ as_type = AS_AUTO;
} else if (!asn_str2asn(as_str, &as))
as_type = AS_UNSPECIFIED;
@@ -4976,13 +4979,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external|auto>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
int idx_peer = 1;
int idx_remote_as = 3;
@@ -5037,7 +5041,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
as_t as = 0;
- int as_type = AS_UNSPECIFIED;
+ enum peer_asn_type as_type = AS_UNSPECIFIED;
struct peer *peer;
struct peer_group *group;
int ret = 0;
@@ -5054,6 +5058,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
as_type = AS_INTERNAL;
} else if (as_str[0] == 'e') {
as_type = AS_EXTERNAL;
+ } else if (as_str[0] == 'a') {
+ as_type = AS_AUTO;
} else {
/* Get AS number. */
if (asn_str2asn(as_str, &as))
@@ -5170,14 +5176,15 @@ DEFUN (neighbor_interface_config_v6only,
DEFUN (neighbor_interface_config_remote_as,
neighbor_interface_config_remote_as_cmd,
- "neighbor WORD interface remote-as <ASNUM|internal|external>",
+ "neighbor WORD interface remote-as <ASNUM|internal|external|auto>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP on interface\n"
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
int idx_word = 1;
int idx_remote_as = 4;
@@ -5187,7 +5194,7 @@ DEFUN (neighbor_interface_config_remote_as,
DEFUN (neighbor_interface_v6only_config_remote_as,
neighbor_interface_v6only_config_remote_as_cmd,
- "neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
+ "neighbor WORD interface v6only remote-as <ASNUM|internal|external|auto>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP with v6 link-local only\n"
@@ -5195,7 +5202,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as,
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
int idx_word = 1;
int idx_remote_as = 5;
@@ -5232,14 +5240,15 @@ DEFUN (neighbor_peer_group,
DEFUN (no_neighbor,
no_neighbor_cmd,
- "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external>]>",
+ "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external|auto>]>",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_peer = 2;
@@ -5310,7 +5319,7 @@ DEFUN (no_neighbor,
DEFUN (no_neighbor_interface_config,
no_neighbor_interface_config_cmd,
- "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]",
+ "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]",
NO_STR
NEIGHBOR_STR
"Interface name\n"
@@ -5321,7 +5330,8 @@ DEFUN (no_neighbor_interface_config,
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_word = 2;
@@ -5378,14 +5388,15 @@ DEFUN (no_neighbor_peer_group,
DEFUN (no_neighbor_interface_peer_group_remote_as,
no_neighbor_interface_peer_group_remote_as_cmd,
- "no neighbor WORD remote-as <ASNUM|internal|external>",
+ "no neighbor WORD remote-as <ASNUM|internal|external|auto>",
NO_STR
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Specify a BGP neighbor\n"
AS_STR
"Internal BGP peer\n"
- "External BGP peer\n")
+ "External BGP peer\n"
+ "Automatically detect remote ASN\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_word = 2;
@@ -11876,7 +11887,8 @@ static char *bgp_peer_description_stripped(char *desc, uint32_t size)
/* Determine whether var peer should be filtered out of the summary. */
static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
- struct peer *fpeer, int as_type,
+ struct peer *fpeer,
+ enum peer_asn_type as_type,
as_t as)
{
@@ -11887,7 +11899,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
/* filter remote-as (internal|external) */
if (as_type != AS_UNSPECIFIED) {
if (peer->as_type == AS_SPECIFIED) {
- if (as_type == AS_INTERNAL) {
+ if (CHECK_FLAG(as_type, AS_INTERNAL)) {
if (peer->as != peer->local_as)
return true;
} else if (peer->as == peer->local_as)
@@ -11910,8 +11922,8 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
* whitespaces and the whole output will be tricky.
*/
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
- struct peer *fpeer, int as_type, as_t as,
- uint16_t show_flags)
+ struct peer *fpeer, enum peer_asn_type as_type,
+ as_t as, uint16_t show_flags)
{
struct peer *peer;
struct listnode *node, *nnode;
@@ -12718,10 +12730,9 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
}
static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
- safi_t safi,
- const char *neighbor,
- int as_type, as_t as,
- uint16_t show_flags)
+ safi_t safi, const char *neighbor,
+ enum peer_asn_type as_type,
+ as_t as, uint16_t show_flags)
{
struct listnode *node, *nnode;
struct bgp *bgp;
@@ -12763,8 +12774,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
}
int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
- safi_t safi, const char *neighbor, int as_type,
- as_t as, uint16_t show_flags)
+ safi_t safi, const char *neighbor,
+ enum peer_asn_type as_type, as_t as,
+ uint16_t show_flags)
{
struct bgp *bgp;
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -12879,6 +12891,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
as_type = AS_INTERNAL;
else if (argv[idx + 1]->arg[0] == 'e')
as_type = AS_EXTERNAL;
+ else if (argv[idx + 1]->arg[0] == 'a')
+ as_type = AS_AUTO;
else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
vty_out(vty,
"%% Invalid neighbor remote-as value: %s\n",
@@ -14002,9 +14016,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_boolean_true_add(json_neigh,
"localAsReplaceAs");
} else {
- if ((p->as_type == AS_SPECIFIED) ||
- (p->as_type == AS_EXTERNAL) ||
- (p->as_type == AS_INTERNAL)) {
+ if (p->as_type == AS_SPECIFIED ||
+ CHECK_FLAG(p->as_type, AS_AUTO) ||
+ CHECK_FLAG(p->as_type, AS_EXTERNAL) ||
+ CHECK_FLAG(p->as_type, AS_INTERNAL)) {
vty_out(vty, "remote AS ");
vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
vty_out(vty, ", ");
@@ -14023,7 +14038,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
: "");
}
/* peer type internal or confed-internal */
- if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) {
+ if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) {
if (use_json) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
json_object_boolean_true_add(
@@ -17011,7 +17026,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
&conf->as);
vty_out(vty, "\n");
}
- } else if (conf->as_type == AS_INTERNAL) {
+ } else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
if (json)
asn_asn2json(json, "remoteAs", group->bgp->as,
group->bgp->asnotation);
@@ -17023,7 +17038,8 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
vty_out(vty, "\nBGP peer-group %s\n", group->name);
}
- if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) {
+ if ((group->bgp->as == conf->as) ||
+ CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
if (json)
json_object_string_add(json_peer_group, "type",
"internal");
@@ -18525,6 +18541,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
} else if (peer->as_type == AS_EXTERNAL) {
vty_out(vty, " remote-as external");
if_ras_printed = true;
+ } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
+ vty_out(vty, " remote-as auto");
+ if_ras_printed = true;
}
vty_out(vty, "\n");
@@ -18547,6 +18566,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty,
" neighbor %s remote-as external\n",
addr);
+ } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
+ vty_out(vty, " neighbor %s remote-as auto\n",
+ addr);
}
}
@@ -18576,6 +18598,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty,
" neighbor %s remote-as external\n",
addr);
+ } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
+ vty_out(vty, " neighbor %s remote-as auto\n",
+ addr);
}
}
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 6d86f6ba08..f88f5c8125 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -161,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
int argc, struct bgp **bgp, bool use_json);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
- safi_t safi, const char *neighbor, int as_type,
- as_t as, uint16_t show_flags);
+ safi_t safi, const char *neighbor,
+ enum peer_asn_type as_type, as_t as,
+ uint16_t show_flags);
extern bool peergroup_flag_check(struct peer *peer, uint64_t flag);
extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
uint64_t flag);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 3508f2d341..72620de7d9 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1556,7 +1556,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
struct peer *peer;
uint32_t metric;
route_tag_t tag;
- bool is_add;
uint32_t nhg_id = 0;
struct bgp_table *table = bgp_dest_table(dest);
const struct prefix *p = bgp_dest_get_prefix(dest);
@@ -1610,9 +1609,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
table->afi, table->safi, &nhg_id,
&metric, &tag, &allow_recursion);
- is_add = (valid_nh_count || nhg_id) ? true : false;
-
- if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
+ if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
struct bgp_zebra_opaque bzo = {};
const char *reason =
bgp_path_selection_reason2str(dest->reason);
@@ -1668,18 +1665,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
}
if (bgp_debug_zebra(p)) {
- zlog_debug("Tx route %s %s %pFX metric %u tag %" ROUTE_TAG_PRI
+ zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d",
- is_add ? "add" : "delete", bgp->name_pretty,
- &api.prefix, api.metric, api.tag, api.nexthop_num,
- nhg_id);
+ bgp->name_pretty, api.tableid, &api.prefix,
+ api.metric, api.tag, api.nexthop_num, nhg_id);
bgp_debug_zebra_nh(&api);
zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)",
__func__, p, (allow_recursion ? "" : "NOT "));
}
- return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
- zclient, &api);
+
+ return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
@@ -1761,8 +1757,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest,
}
if (bgp_debug_zebra(p))
- zlog_debug("Tx route delete %s %pFX", bgp->name_pretty,
- &api.prefix);
+ zlog_debug("Tx route delete %s (table id %u) %pFX",
+ bgp->name_pretty, api.tableid, &api.prefix);
return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 17d94bd575..3810413adc 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
/* Peer-group */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- if (peer->as_type == AS_INTERNAL)
+ if (CHECK_FLAG(peer->as_type, AS_INTERNAL))
return BGP_PEER_IBGP;
- else if (peer->as_type == AS_EXTERNAL)
+ if (CHECK_FLAG(peer->as_type, AS_EXTERNAL))
return BGP_PEER_EBGP;
else if (peer->as_type == AS_SPECIFIED && peer->as) {
@@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
return BGP_PEER_IBGP;
else
return BGP_PEER_EBGP;
- } else if (peer->group->conf->as_type
- == AS_INTERNAL)
+ } else if (CHECK_FLAG(peer->group->conf->as_type,
+ AS_INTERNAL))
return BGP_PEER_IBGP;
else
return BGP_PEER_EBGP;
}
/* no AS information anywhere, let caller know */
return BGP_PEER_UNSPECIFIED;
- } else if (peer->as_type != AS_SPECIFIED)
- return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
- : BGP_PEER_EBGP);
+ } else if (peer->as_type != AS_SPECIFIED) {
+ if (CHECK_FLAG(peer->as_type, AS_INTERNAL))
+ return BGP_PEER_IBGP;
+ else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL))
+ return BGP_PEER_EBGP;
+ }
return (local_as == 0 ? BGP_PEER_INTERNAL
: local_as == peer->as ? BGP_PEER_IBGP
@@ -1949,7 +1952,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
*/
struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
- int as_type, struct peer_group *group,
+ enum peer_asn_type as_type, struct peer_group *group,
bool config_node, const char *as_str)
{
int active;
@@ -2081,7 +2084,7 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
}
/* Change peer's AS number. */
-void peer_as_change(struct peer *peer, as_t as, int as_specified,
+void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type,
const char *as_str)
{
enum bgp_peer_sort origtype, newtype;
@@ -2097,13 +2100,13 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified,
}
origtype = peer_sort_lookup(peer);
peer->as = as;
- if (as_specified == AS_SPECIFIED && as_str) {
+ if (as_type == AS_SPECIFIED && as_str) {
if (peer->as_pretty)
XFREE(MTYPE_BGP_NAME, peer->as_pretty);
peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str);
} else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty)
XFREE(MTYPE_BGP_NAME, peer->as_pretty);
- peer->as_type = as_specified;
+ peer->as_type = as_type;
if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
&& !bgp_confederation_peers_check(peer->bgp, as)
@@ -2160,7 +2163,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified,
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
- as_t *as, int as_type, const char *as_str)
+ as_t *as, enum peer_asn_type as_type, const char *as_str)
{
struct peer *peer;
as_t local_as;
@@ -2201,10 +2204,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
}
} else {
/* internal/external used, compare as-types */
- if (((peer_sort_type == BGP_PEER_IBGP)
- && (as_type != AS_INTERNAL))
- || ((peer_sort_type == BGP_PEER_EBGP)
- && (as_type != AS_EXTERNAL))) {
+ if (((peer_sort_type == BGP_PEER_IBGP) &&
+ !CHECK_FLAG(as_type, AS_INTERNAL)) ||
+ ((peer_sort_type == BGP_PEER_EBGP) &&
+ !CHECK_FLAG(as_type, AS_EXTERNAL))) {
*as = peer->as;
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
}
@@ -3025,7 +3028,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
/* Peer group's remote AS configuration. */
int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
- int as_type, const char *as_str)
+ enum peer_asn_type as_type, const char *as_str)
{
struct peer_group *group;
struct peer *peer;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 3c5826113d..95ddba4cdd 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -56,10 +56,12 @@ struct bgp_pbr_config;
* behavior
* in the system.
*/
-enum { AS_UNSPECIFIED = 0,
- AS_SPECIFIED,
- AS_INTERNAL,
- AS_EXTERNAL,
+enum peer_asn_type {
+ AS_UNSPECIFIED = 1,
+ AS_SPECIFIED = 2,
+ AS_INTERNAL = 4,
+ AS_EXTERNAL = 8,
+ AS_AUTO = 16,
};
/* Zebra Gracaful Restart states */
@@ -1246,7 +1248,7 @@ struct peer {
struct peer_af *peer_af_array[BGP_AF_MAX];
/* Peer's remote AS number. */
- int as_type;
+ enum peer_asn_type as_type;
as_t as;
/* for vty as format */
char *as_pretty;
@@ -2281,8 +2283,9 @@ extern bool peer_afc_advertised(struct peer *peer);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
extern struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
- int as_type, struct peer_group *group,
- bool config_node, const char *as_str);
+ enum peer_asn_type as_type,
+ struct peer_group *group, bool config_node,
+ const char *as_str);
extern struct peer *peer_create_accept(struct bgp *);
extern void peer_xfer_config(struct peer *dst, struct peer *src);
extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
@@ -2355,13 +2358,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp);
extern bool bgp_update_delay_active(struct bgp *);
extern bool bgp_update_delay_configured(struct bgp *);
extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
-extern void peer_as_change(struct peer *peer, as_t as, int as_type,
- const char *as_str);
+extern void peer_as_change(struct peer *peer, as_t as,
+ enum peer_asn_type as_type, const char *as_str);
extern int peer_remote_as(struct bgp *bgp, union sockunion *su,
- const char *conf_if, as_t *as, int as_type,
- const char *as_str);
+ const char *conf_if, as_t *as,
+ enum peer_asn_type as_type, const char *as_str);
extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as,
- int as_type, const char *as_str);
+ enum peer_asn_type as_type, const char *as_str);
extern int peer_delete(struct peer *peer);
extern void peer_notify_unconfig(struct peer *peer);
extern int peer_group_delete(struct peer_group *);
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 98834c7c23..a569a9af28 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1561,6 +1561,10 @@ Defining Peers
peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN`
command the connection will be denied.
+.. clicmd:: neighbor PEER remote-as auto
+
+ The neighbor's ASN is detected automatically from the OPEN message.
+
.. clicmd:: neighbor PEER oad
Mark a peer belonging to the One Administrative Domain.
@@ -1699,7 +1703,7 @@ Configuring Peers
IPv4 session addresses, see the ``neighbor PEER update-source`` command
below.
-.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN>
+.. clicmd:: neighbor PEER interface remote-as <internal|external|auto|ASN>
Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
session will be established via IPv6 link locals. Use ``internal`` for iBGP
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index b81a0cc2f0..3ed6fe95f5 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj)
struct isis_dynhn *dyn;
dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
- if (dyn)
+ if (adj->circuit->area->dynhostname && dyn)
return dyn->hostname;
snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 13f5148d4a..bda7ed89a4 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -482,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
lsp->tlvs = tlvs;
- if (area->dynhostname && lsp->tlvs->hostname
- && lsp->hdr.rem_lifetime) {
- isis_dynhn_insert(
- area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
- (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
- ? IS_LEVEL_2
- : IS_LEVEL_1);
+ if (area->dynhostname && lsp->hdr.rem_lifetime) {
+ if (lsp->tlvs->hostname) {
+ isis_dynhn_insert(area->isis, lsp->hdr.lsp_id,
+ lsp->tlvs->hostname,
+ (lsp->hdr.lsp_bits & LSPBIT_IST) ==
+ IS_LEVEL_1_AND_2
+ ? IS_LEVEL_2
+ : IS_LEVEL_1);
+ } else {
+ if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) &&
+ !LSP_FRAGMENT(lsp->hdr.lsp_id))
+ isis_dynhn_remove(area->isis, lsp->hdr.lsp_id);
+ }
}
return;
@@ -2220,6 +2226,10 @@ void lsp_tick(struct event *thread)
&area->lspdb[level],
next);
+ if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id))
+ isis_dynhn_remove(area->isis,
+ lsp->hdr.lsp_id);
+
lspdb_del(&area->lspdb[level], lsp);
lsp_destroy(lsp);
lsp = NULL;
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 30c90baa54..8926b624ea 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
return NB_ERR_INCONSISTENCY;
listnode_delete(area->area_addrs, addrp);
- XFREE(MTYPE_ISIS_AREA_ADDR, addrp);
/*
* Last area address - reset the SystemID for this router
*/
- if (listcount(area->area_addrs) == 0) {
+ if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid,
+ ISIS_SYS_ID_LEN) &&
+ listcount(area->area_addrs) == 0) {
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
if (circuit->u.bc.is_dr[lvl - 1])
@@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
zlog_debug("Router has no SystemID");
}
+ XFREE(MTYPE_ISIS_AREA_ADDR, addrp);
+
return NB_OK;
}
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 982df0839b..8db6295b66 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -496,6 +496,7 @@ void isis_area_destroy(struct isis_area *area)
{
struct listnode *node, *nnode;
struct isis_circuit *circuit;
+ struct iso_address *addr;
QOBJ_UNREG(area);
@@ -545,6 +546,15 @@ void isis_area_destroy(struct isis_area *area)
if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
isis_redist_area_finish(area);
+ if (listcount(area->area_addrs) > 0) {
+ addr = listgetdata(listhead(area->area_addrs));
+ if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid,
+ ISIS_SYS_ID_LEN)) {
+ memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 0;
+ }
+ }
+
list_delete(&area->area_addrs);
for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM;
diff --git a/lib/frrcu.h b/lib/frrcu.h
index 9f07a69b52..81ab5528a9 100644
--- a/lib/frrcu.h
+++ b/lib/frrcu.h
@@ -156,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action);
#define rcu_call(func, ptr, field) \
do { \
typeof(ptr) _ptr = (ptr); \
- void (*fptype)(typeof(ptr)); \
+ void (*_fptype)(typeof(ptr)); \
struct rcu_head *_rcu_head = &_ptr->field; \
static const struct rcu_action _rcu_action = { \
.type = RCUA_CALL, \
diff --git a/lib/libospf.h b/lib/libospf.h
index f2dc5d61d9..8a208beb3c 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -61,6 +61,7 @@ extern "C" {
#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */
#define OSPF_TRANSMIT_DELAY_DEFAULT 1
#define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */
+#define OSPF_ACK_DELAY_DEFAULT 1
#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */
diff --git a/lib/seqlock.c b/lib/seqlock.c
index 62ce316920..e74e6718bf 100644
--- a/lib/seqlock.c
+++ b/lib/seqlock.c
@@ -26,6 +26,39 @@
* OS specific synchronization wrappers *
****************************************/
+#ifndef __has_feature /* not available on old GCC */
+#define __has_feature(x) 0
+#endif
+
+#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer))
+/* TSAN really does not understand what is going on with the low-level
+ * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which
+ * also have _extremely_ misleading text - since TSAN does not understand that
+ * there is in fact a synchronization primitive involved, it can end up pulling
+ * in completely unrelated things.
+ *
+ * What does work is the "unsupported platform" seqlock implementation based
+ * on a pthread mutex + condvar, since TSAN of course suppports these.
+ *
+ * It may be possible to also fix this with TSAN annotations (__tsan_acquire
+ * and __tsan_release), but using those (correctly) is not easy either, and
+ * for now just get things rolling.
+ */
+
+#ifdef HAVE_SYNC_LINUX_FUTEX
+#undef HAVE_SYNC_LINUX_FUTEX
+#endif
+
+#ifdef HAVE_SYNC_OPENBSD_FUTEX
+#undef HAVE_SYNC_OPENBSD_FUTEX
+#endif
+
+#ifdef HAVE_SYNC_UMTX_OP
+#undef HAVE_SYNC_UMTX_OP
+#endif
+
+#endif /* TSAN */
+
/*
* Linux: sys_futex()
*/
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index e9797ce935..2af4ae3170 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area)
static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr,
struct ospf_lsa *lsa)
{
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
+ struct ospf_interface *oi = inbr->oi;
+
/* LSA is more recent than database copy, but was not
flooded back out receiving interface. Delayed
acknowledgment sent. If interface is in Backup state
@@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr,
worked out previously */
/* Deal with router as BDR */
- if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr))
+ if (oi->state == ISM_Backup && !NBR_IS_DR(inbr))
return;
- /* Schedule a delayed LSA Ack to be sent */
- listnode_add(inbr->oi->ls_ack,
- ospf_lsa_lock(lsa)); /* delayed LSA Ack */
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue",
+ __func__, lsa->data->type, &lsa->data->id,
+ &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum),
+ ntohs(lsa->data->ls_age), &inbr->router_id,
+ IF_NAME(inbr->oi));
+
+ /* Add the LSA to the interface delayed Ack list. */
+ ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST,
+ sizeof(struct ospf_lsa_list_entry));
+ ls_ack_list_entry->lsa = ospf_lsa_lock(lsa);
+ ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry);
+
+ /* Set LS Ack timer if it is not already scheduled. */
+ if (!oi->t_ls_ack_delayed)
+ OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed,
+ ospf_ls_ack_delayed_timer,
+ oi->v_ls_ack_delayed);
}
/* Check LSA is related to external info. */
diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h
index d9d9537351..2412052970 100644
--- a/ospfd/ospf_flood.h
+++ b/ospfd/ospf_flood.h
@@ -7,6 +7,8 @@
#ifndef _ZEBRA_OSPF_FLOOD_H
#define _ZEBRA_OSPF_FLOOD_H
+#include "typesafe.h"
+
/*
* OSPF Temporal LSA List
*/
@@ -16,14 +18,25 @@ struct ospf_lsa_list_entry {
/* Linkage for LSA List */
struct ospf_lsa_list_item list_linkage;
- /*
- * Time associated with the list entry. For example, for a neigbhor
- * link retransmission list, this is the retransmission time.
- */
- struct timeval list_entry_time;
+ union {
+ /*
+ * Time associated with the list entry. For example, for a
+ * neigbhor link retransmission list, this is the
+ * retransmission time.
+ */
+ struct timeval list_entry_timeval;
+
+ /*
+ * Destanation address specific to the LSA list. For example,
+ * the distination for an associated direct LS acknowledgment.
+ */
+ struct in_addr list_entry_dst_addr;
+ } u;
struct ospf_lsa *lsa;
};
+#define list_entry_time u.list_entry_timeval
+#define list_entry_dst u.list_entry_dst_addr
DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage);
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 803c36861d..c4210eb70c 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -186,10 +186,12 @@ static void ospf_if_default_variables(struct ospf_interface *oi)
oi->crypt_seqnum = 0;
- /* This must be short, (less than RxmtInterval)
- - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being
- held back for too long - MAG */
- oi->v_ls_ack = 1;
+ /*
+ * The OSPF LS ACK Delay timer must be less than the LS Retransmision
+ * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second
+ * to avoid Acks being held back for too long
+ */
+ oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT;
}
/* lookup oi for specified prefix/ifp */
@@ -272,9 +274,9 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp,
/* Initialize static neighbor list. */
oi->nbr_nbma = list_new();
- /* Initialize Link State Acknowledgment list. */
- oi->ls_ack = list_new();
- oi->ls_ack_direct.ls_ack = list_new();
+ /* Initialize Link State Acknowledgment lists. */
+ ospf_lsa_list_init(&oi->ls_ack_delayed);
+ ospf_lsa_list_init(&oi->ls_ack_direct);
/* Set default values. */
ospf_if_default_variables(oi);
@@ -306,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp,
return oi;
}
+/*
+ * Cleanup Interface Ack List
+ */
+static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list)
+{
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
+ struct ospf_lsa *lsa;
+
+ frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) {
+ lsa = ls_ack_list_entry->lsa;
+ ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry);
+ ospf_lsa_unlock(&lsa);
+ }
+}
+
/* Restore an interface to its pre UP state
Used from ism_interface_down only */
void ospf_if_cleanup(struct ospf_interface *oi)
@@ -314,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi)
struct listnode *node, *nnode;
struct ospf_neighbor *nbr;
struct ospf_nbr_nbma *nbr_nbma;
- struct ospf_lsa *lsa;
/* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */
/* delete all static neighbors attached to this interface */
@@ -338,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi)
OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
}
- /* Cleanup Link State Acknowlegdment list. */
- for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa))
- ospf_lsa_unlock(&lsa); /* oi->ls_ack */
- list_delete_all_node(oi->ls_ack);
+ /* Cleanup Link State Delayed Acknowlegdment list. */
+ ospf_if_cleanup_ack_list(&oi->ls_ack_delayed);
+ ospf_if_cleanup_ack_list(&oi->ls_ack_direct);
oi->crypt_seqnum = 0;
@@ -377,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi)
/* Free any lists that should be freed */
list_delete(&oi->nbr_nbma);
- list_delete(&oi->ls_ack);
- list_delete(&oi->ls_ack_direct.ls_ack);
+ ospf_if_cleanup_ack_list(&oi->ls_ack_delayed);
+ ospf_if_cleanup_ack_list(&oi->ls_ack_direct);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: ospf interface %s vrf %s id %u deleted",
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index a944847b5d..78a4fb9e59 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -13,6 +13,7 @@
#include "keychain.h"
#include "ospfd/ospf_packet.h"
#include "ospfd/ospf_spf.h"
+#include <ospfd/ospf_flood.h>
#define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info))
#define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params)
@@ -265,20 +266,20 @@ struct ospf_interface {
struct route_table *ls_upd_queue;
- struct list *ls_ack; /* Link State Acknowledgment list. */
-
- struct {
- struct list *ls_ack;
- struct in_addr dst;
- } ls_ack_direct;
+ /*
+ * List of LSAs for delayed and direct link
+ * state acknowledgment transmission.
+ */
+ struct ospf_lsa_list_head ls_ack_delayed;
+ struct ospf_lsa_list_head ls_ack_direct;
/* Timer values. */
- uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */
+ uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */
/* Threads. */
struct event *t_hello; /* timer */
struct event *t_wait; /* timer */
- struct event *t_ls_ack; /* timer */
+ struct event *t_ls_ack_delayed; /* timer */
struct event *t_ls_ack_direct; /* event */
struct event *t_ls_upd_event; /* event */
struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */
diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c
index 878ab725bd..377e7a6bcc 100644
--- a/ospfd/ospf_ism.c
+++ b/ospfd/ospf_ism.c
@@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi)
reset also. */
EVENT_OFF(oi->t_hello);
EVENT_OFF(oi->t_wait);
- EVENT_OFF(oi->t_ls_ack);
+ EVENT_OFF(oi->t_ls_ack_delayed);
EVENT_OFF(oi->gr.hello_delay.t_grace_send);
break;
case ISM_Loopback:
@@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi)
unavailable for regular data traffic. */
EVENT_OFF(oi->t_hello);
EVENT_OFF(oi->t_wait);
- EVENT_OFF(oi->t_ls_ack);
+ EVENT_OFF(oi->t_ls_ack_delayed);
EVENT_OFF(oi->gr.hello_delay.t_grace_send);
break;
case ISM_Waiting:
@@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi)
OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer,
OSPF_IF_PARAM(oi, v_wait));
- EVENT_OFF(oi->t_ls_ack);
+ EVENT_OFF(oi->t_ls_ack_delayed);
break;
case ISM_PointToPoint:
/* The interface connects to a physical Point-to-point network
@@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi)
/* send first hello immediately */
OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
EVENT_OFF(oi->t_wait);
- OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
- oi->v_ls_ack);
break;
case ISM_DROther:
/* The network type of the interface is broadcast or NBMA
@@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi)
Backup Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
EVENT_OFF(oi->t_wait);
- OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
- oi->v_ls_ack);
break;
case ISM_Backup:
/* The network type of the interface is broadcast os NBMA
@@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi)
and the router is Backup Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
EVENT_OFF(oi->t_wait);
- OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
- oi->v_ls_ack);
break;
case ISM_DR:
/* The network type of the interface is broadcast or NBMA
@@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi)
and the router is Designated Router. */
OSPF_HELLO_TIMER_ON(oi);
EVENT_OFF(oi->t_wait);
- OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
- oi->v_ls_ack);
break;
}
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 86f877b621..2d15a7ecca 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -369,19 +369,16 @@ void ospf_ls_rxmt_timer(struct event *thread)
ospf_ls_retransmit_set_timer(nbr);
}
-void ospf_ls_ack_timer(struct event *thread)
+void ospf_ls_ack_delayed_timer(struct event *thread)
{
struct ospf_interface *oi;
oi = EVENT_ARG(thread);
- oi->t_ls_ack = NULL;
+ oi->t_ls_ack_delayed = NULL;
/* Send Link State Acknowledgment. */
- if (listcount(oi->ls_ack) > 0)
+ if (ospf_lsa_list_count(&oi->ls_ack_delayed))
ospf_ls_ack_send_delayed(oi);
-
- /* Set LS Ack timer. */
- OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
}
#ifdef WANT_OSPF_WRITE_FRAGMENT
@@ -1820,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
if (IS_LSA_MAXAGE(lsa) && !current
&& ospf_check_nbr_status(oi->ospf)) {
/* (4a) Response Link State Acknowledgment. */
- ospf_ls_ack_send(nbr, lsa);
+ ospf_ls_ack_send_direct(nbr, lsa);
/* (4b) Discard LSA. */
if (IS_DEBUG_OSPF(lsa, LSA)) {
@@ -1845,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
if (IS_LSA_MAXAGE(lsa)) {
zlog_info("LSA[%s]: Boomerang effect?",
dump_lsa_key(lsa));
- ospf_ls_ack_send(nbr, lsa);
+ ospf_ls_ack_send_direct(nbr, lsa);
ospf_lsa_discard(lsa);
if (current != NULL && !IS_LSA_MAXAGE(current))
@@ -1879,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
SET_FLAG(lsa->flags, OSPF_LSA_SELF);
- ospf_ls_ack_send(nbr, lsa);
+ ospf_ls_ack_send_direct(nbr, lsa);
if (!ospf->gr_info.restart_in_progress) {
ospf_opaque_self_originated_lsa_received(
@@ -2018,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
*/
if (oi->state == ISM_Backup)
if (NBR_IS_DR(nbr))
- listnode_add(
- oi->ls_ack,
- ospf_lsa_lock(lsa));
+ ospf_ls_ack_send_direct(nbr,
+ lsa);
DISCARD_LSA(lsa, 6);
} else
@@ -2029,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
receiving
interface. */
{
- ospf_ls_ack_send(nbr, lsa);
+ ospf_ls_ack_send_direct(nbr, lsa);
DISCARD_LSA(lsa, 7);
}
}
@@ -3331,17 +3327,36 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
return length;
}
-static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
- struct stream *s)
+static int ospf_make_ls_ack(struct ospf_interface *oi,
+ struct ospf_lsa_list_head *ls_ack_list,
+ bool direct_ack, bool delete_ack, struct stream *s)
{
- struct listnode *node, *nnode;
+ struct ospf_lsa_list_entry *ls_ack_list_first;
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
- unsigned long delta = OSPF_LSA_HEADER_SIZE;
struct ospf_lsa *lsa;
+ struct in_addr first_dst_addr;
- for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
+ /*
+ * For direct LS Acks, assure the destination address doesn't
+ * change between queued acknowledgments.
+ */
+ if (direct_ack) {
+ ls_ack_list_first = ospf_lsa_list_first(ls_ack_list);
+ if (ls_ack_list_first)
+ first_dst_addr.s_addr =
+ ls_ack_list_first->list_entry_dst.s_addr;
+ } else
+ first_dst_addr.s_addr = INADDR_ANY;
+
+ frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) {
+ lsa = ls_ack_list_entry->lsa;
assert(lsa);
+ if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr !=
+ first_dst_addr.s_addr))
+ break;
+
/* LS Ack packet overflows interface MTU
* delta is just number of bytes required for
* 1 LS Ack(1 LS Hdr) ospf_packet_max will return
@@ -3350,19 +3365,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
* against ospf_packet_max to check if it can fit
* another ls header in the same packet.
*/
- if ((length + delta) > ospf_packet_max(oi))
+ if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi))
break;
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
length += OSPF_LSA_HEADER_SIZE;
- listnode_delete(ack, lsa);
- ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */
+ if (delete_ack) {
+ ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry);
+ ospf_lsa_unlock(&lsa);
+ }
}
return length;
}
+/*
+ * On non-braodcast networks, the same LS acks must be sent to multiple
+ * neighbors and deletion must be deferred until after the LS Ack packet
+ * is sent to all neighbors.
+ */
+static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi)
+{
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
+ struct ospf_lsa *lsa;
+ uint16_t length = OSPF_LS_ACK_MIN_SIZE;
+
+ frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) {
+ lsa = ls_ack_list_entry->lsa;
+ assert(lsa);
+ if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi))
+ break;
+
+ length += OSPF_LSA_HEADER_SIZE;
+ ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry);
+ ospf_lsa_unlock(&lsa);
+ }
+}
+
static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr)
{
struct ospf_packet *op;
@@ -3934,10 +3976,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag,
&oi->t_ls_upd_event);
}
-static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
+static void ospf_ls_ack_send_list(struct ospf_interface *oi,
+ struct ospf_lsa_list_head *ls_ack_list,
+ bool direct_ack, bool delete_ack,
struct in_addr dst)
{
struct ospf_packet *op;
+ struct ospf_lsa_list_entry *ls_ack_list_first;
uint16_t length = OSPF_HEADER_SIZE;
op = ospf_packet_new(oi->ifp->mtu);
@@ -3945,8 +3990,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
/* Prepare OSPF common header. */
ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s);
+ /* Determine the destination address - for direct acks,
+ * the list entries always include the distination address.
+ */
+ if (direct_ack) {
+ ls_ack_list_first = ospf_lsa_list_first(ls_ack_list);
+ op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr;
+ } else
+ op->dst.s_addr = dst.s_addr;
+
/* Prepare OSPF Link State Acknowledgment body. */
- length += ospf_make_ls_ack(oi, ack, op->s);
+ length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack,
+ op->s);
/* Fill OSPF header. */
ospf_fill_header(oi, op->s, length);
@@ -3954,14 +4009,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
/* Set packet length. */
op->length = length;
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
- (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT &&
- !oi->p2mp_non_broadcast))
- op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
- else
- op->dst.s_addr = dst.s_addr;
-
/* Add packet to the interface output queue. */
ospf_packet_add(oi, op);
@@ -3969,34 +4016,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
OSPF_ISM_WRITE_ON(oi->ospf);
}
-static void ospf_ls_ack_send_event(struct event *thread)
+static void ospf_ls_ack_send_direct_event(struct event *thread)
{
struct ospf_interface *oi = EVENT_ARG(thread);
+ struct in_addr dst = { INADDR_ANY };
oi->t_ls_ack_direct = NULL;
- while (listcount(oi->ls_ack_direct.ls_ack))
- ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack,
- oi->ls_ack_direct.dst);
+ while (ospf_lsa_list_count(&oi->ls_ack_direct))
+ ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst);
}
-void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
struct ospf_interface *oi = nbr->oi;
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue",
+ __func__, lsa->data->type, &lsa->data->id,
+ &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum),
+ ntohs(lsa->data->ls_age), &nbr->router_id,
+ IF_NAME(nbr->oi));
+
+ /*
+ * On Point-to-Multipoint broadcast-capabile interfaces,
+ * where direct acks from are sent to the ALLSPFRouters
+ * address and one direct ack send event, may include LSAs
+ * from multiple neighbors, there is a possibility of the same
+ * LSA being processed more than once in the same send event.
+ * In this case, the instances subsequent to the first can be
+ * ignored.
+ */
+ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) {
+ struct ospf_lsa_list_entry *ls_ack_list_entry;
+ struct ospf_lsa *ack_queue_lsa;
+
+ frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) {
+ ack_queue_lsa = ls_ack_list_entry->lsa;
+ if ((lsa == ack_queue_lsa) ||
+ ((lsa->data->type == ack_queue_lsa->data->type) &&
+ (lsa->data->id.s_addr ==
+ ack_queue_lsa->data->id.s_addr) &&
+ (lsa->data->adv_router.s_addr ==
+ ack_queue_lsa->data->adv_router.s_addr) &&
+ (lsa->data->ls_seqnum ==
+ ack_queue_lsa->data->ls_seqnum))) {
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate",
+ __func__, lsa->data->type,
+ &lsa->data->id,
+ &lsa->data->adv_router,
+ ntohl(lsa->data->ls_seqnum),
+ ntohs(lsa->data->ls_age),
+ &nbr->router_id,
+ IF_NAME(nbr->oi));
+ return;
+ }
+ }
+ }
+
if (IS_GRACE_LSA(lsa)) {
if (IS_DEBUG_OSPF_GR)
zlog_debug("%s, Sending GRACE ACK to Restarter.",
__func__);
}
- if (listcount(oi->ls_ack_direct.ls_ack) == 0)
- oi->ls_ack_direct.dst = nbr->address.u.prefix4;
+ ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST,
+ sizeof(struct ospf_lsa_list_entry));
- listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa));
+ /*
+ * Determine the destination address - Direct LS acknowledgments
+ * are sent the AllSPFRouters multicast address on Point-to-Point
+ * and Point-to-Multipoint broadcast-capable interfaces. For all other
+ * interface types, they are unicast directly to the neighbor.
+ */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
+ (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT &&
+ !oi->p2mp_non_broadcast))
+ ls_ack_list_entry->list_entry_dst.s_addr =
+ htonl(OSPF_ALLSPFROUTERS);
+ else
+ ls_ack_list_entry->list_entry_dst.s_addr =
+ nbr->address.u.prefix4.s_addr;
- event_add_event(master, ospf_ls_ack_send_event, oi, 0,
- &oi->t_ls_ack_direct);
+ ls_ack_list_entry->lsa = ospf_lsa_lock(lsa);
+ ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry);
+
+ if (oi->t_ls_ack_direct == NULL)
+ event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0,
+ &oi->t_ls_ack_direct);
}
/* Send Link State Acknowledgment delayed. */
@@ -4013,33 +4122,39 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi)
struct ospf_neighbor *nbr;
struct route_node *rn;
- for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
- nbr = rn->info;
+ while (ospf_lsa_list_count(&oi->ls_ack_delayed)) {
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
- if (!nbr)
- continue;
+ if (!nbr)
+ continue;
- if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
- while (listcount(oi->ls_ack))
- ospf_ls_ack_send_list(
- oi, oi->ls_ack,
- nbr->address.u.prefix4);
+ if (nbr != oi->nbr_self &&
+ nbr->state >= NSM_Exchange)
+ ospf_ls_ack_send_list(oi,
+ &oi->ls_ack_delayed,
+ false, false,
+ nbr->address.u
+ .prefix4);
+ }
+ ospf_delete_ls_ack_delayed(oi);
}
- return;
- }
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- dst.s_addr = oi->vl_data->peer_addr.s_addr;
- else if (oi->state == ISM_DR || oi->state == ISM_Backup)
- dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
- else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
- else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
- dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
- else
- dst.s_addr = htonl(OSPF_ALLDROUTERS);
+ } else {
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ dst.s_addr = oi->vl_data->peer_addr.s_addr;
+ else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ dst.s_addr = htonl(OSPF_ALLDROUTERS);
- while (listcount(oi->ls_ack))
- ospf_ls_ack_send_list(oi, oi->ls_ack, dst);
+ while (ospf_lsa_list_count(&oi->ls_ack_delayed))
+ ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false,
+ true, dst);
+ }
}
/*
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
index 2c9dba6c88..84e4b027e6 100644
--- a/ospfd/ospf_packet.h
+++ b/ospfd/ospf_packet.h
@@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int);
extern void ospf_ls_upd_queue_send(struct ospf_interface *oi,
struct list *update, struct in_addr addr,
int send_lsupd_now);
-extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *);
+extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr,
+ struct ospf_lsa *lsa);
extern void ospf_ls_ack_send_delayed(struct ospf_interface *);
extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *);
extern void ospf_ls_req_event(struct ospf_neighbor *);
extern void ospf_ls_rxmt_timer(struct event *thread);
-extern void ospf_ls_ack_timer(struct event *thread);
+extern void ospf_ls_ack_delayed_timer(struct event *thread);
extern void ospf_poll_timer(struct event *thread);
extern void ospf_hello_reply_timer(struct event *thread);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 133da918fa..1048436b43 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -247,12 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
memcpy(&api.prefix, p, sizeof(*p));
api.flags = flags;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
/* Only send via ID if nhgroup has been successfully installed */
if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) {
zapi_route_set_nhg_id(&api, &nhgid);
} else {
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
for (ALL_NEXTHOPS_PTR(nhg, nh)) {
/* Check if we set a VNI label */
if (nh->nh_label &&
diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c
index b50216cf92..afcfa98791 100644
--- a/tests/lib/test_atomlist.c
+++ b/tests/lib/test_atomlist.c
@@ -62,7 +62,7 @@ static struct asort_head shead;
static struct testthread {
pthread_t pt;
struct seqlock sqlo;
- size_t counter, nullops;
+ _Atomic size_t counter, nullops;
} thr[NTHREADS];
struct testrun {
@@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \
{ \
size_t i = 0, n = 0;
-#define endtestrun \
- thr[offset].counter = i; \
- thr[offset].nullops = n; \
-}
+#define endtestrun \
+ atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \
+ atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \
+ }
deftestrun(add, "add vs. add", 0, false)
for (; i < NITEM / NTHREADS; i++)
@@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr)
sv = seqlock_bump(&sqlo) - SEQLOCK_INCR;
for (size_t i = 0; i < NTHREADS; i++) {
seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo));
- s += thr[i].counter;
- n += thr[i].nullops;
- thr[i].counter = 0;
- thr[i].nullops = 0;
+ s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst);
+ n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst);
+ atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst);
+ atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst);
}
delta = monotime_since(&tv, NULL);
diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c
index 288d4a8c25..937b3f34f5 100644
--- a/tests/lib/test_seqlock.c
+++ b/tests/lib/test_seqlock.c
@@ -82,11 +82,11 @@ int main(int argc, char **argv)
assert(seqlock_held(&sqlo));
assert(seqlock_cur(&sqlo) == 1);
- assert(seqlock_bump(&sqlo) == 1);
- assert(seqlock_cur(&sqlo) == 5);
assert(seqlock_bump(&sqlo) == 5);
+ assert(seqlock_cur(&sqlo) == 5);
assert(seqlock_bump(&sqlo) == 9);
assert(seqlock_bump(&sqlo) == 13);
+ assert(seqlock_bump(&sqlo) == 17);
assert(seqlock_cur(&sqlo) == 17);
assert(seqlock_held(&sqlo));
@@ -111,4 +111,5 @@ int main(int argc, char **argv)
writestr("main @release\n");
seqlock_release(&sqlo);
sleep(1);
+ pthread_join(thr1, NULL);
}
diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py
index 955881e6f9..83fae71bf5 100644
--- a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py
+++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py
@@ -320,7 +320,7 @@ def check_ipv4_prefix_recursive_with_multiple_nexthops(
)
test_func = functools.partial(
- ip_check_path_selection, tgen.gears["r1"], prefix, expected
+ ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert (
diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py
index a2ca37a2b7..bb779462db 100644
--- a/tests/topotests/bgp_oad/test_bgp_oad.py
+++ b/tests/topotests/bgp_oad/test_bgp_oad.py
@@ -46,7 +46,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def test_bgp_dynamic_capability_role():
+def test_bgp_oad():
tgen = get_topogen()
if tgen.routers_have_failure():
diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json
index 22ec2c298b..483165c0f3 100644
--- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json
+++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json
@@ -23,7 +23,7 @@
"recursive":true
},
{
- "fib":true,
+ "duplicate":true,
"ip":"10.0.3.2",
"active":true
}
diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json
index facddcda46..638a825395 100644
--- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json
+++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json
@@ -23,7 +23,7 @@
"recursive":true
},
{
- "fib":true,
+ "duplicate":true,
"ip":"10.0.3.2",
"active":true
}
diff --git a/tests/topotests/bgp_remote_as_auto/__init__.py b/tests/topotests/bgp_remote_as_auto/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/__init__.py
diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf
new file mode 100644
index 0000000000..2f1bcd275f
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf
@@ -0,0 +1,23 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+int r1-eth1
+ ip address 192.168.14.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.2 remote-as auto
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.1.3 remote-as auto
+ neighbor 192.168.1.3 timers 1 3
+ neighbor 192.168.1.3 timers connect 1
+ neighbor r1-eth1 interface remote-as auto
+ neighbor r1-eth1 timers 1 3
+ neighbor r1-eth1 timers connect 1
+ address-family ipv4 unicast
+ network 10.0.0.1/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf
new file mode 100644
index 0000000000..f8d19a0bfd
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf
@@ -0,0 +1,10 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as auto
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf
new file mode 100644
index 0000000000..fc6862764f
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/r3/frr.conf
@@ -0,0 +1,10 @@
+!
+int r3-eth0
+ ip address 192.168.1.3/24
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as auto
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf
new file mode 100644
index 0000000000..e280a6c6e8
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf
@@ -0,0 +1,10 @@
+!
+int r4-eth0
+ ip address 192.168.14.4/24
+!
+router bgp 65004
+ no bgp ebgp-requires-policy
+ neighbor r4-eth0 interface remote-as auto
+ neighbor r4-eth0 timers 1 3
+ neighbor r4-eth0 timers connect 1
+!
diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py
new file mode 100644
index 0000000000..1db6d98a42
--- /dev/null
+++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+import os
+import re
+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, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2", "r3"), "s2": ("r1", "r4")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_remote_as_auto():
+ 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_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json"))
+ expected = {
+ "peers": {
+ "r1-eth1": {
+ "hostname": "r4",
+ "remoteAs": 65004,
+ "localAs": 65001,
+ "state": "Established",
+ },
+ "192.168.1.2": {
+ "hostname": "r2",
+ "remoteAs": 65001,
+ "localAs": 65001,
+ "state": "Established",
+ },
+ "192.168.1.3": {
+ "hostname": "r3",
+ "remoteAs": 65003,
+ "localAs": 65001,
+ "state": "Established",
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see automatic iBGP/eBGP peerings"
+
+ def _bgp_converge_internal():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aspath": {
+ "string": "Local",
+ },
+ "valid": True,
+ "peer": {
+ "hostname": "r1",
+ "type": "internal",
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge_internal,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see automatic iBGP peering"
+
+ def _bgp_converge_external():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aspath": {
+ "string": "65001",
+ },
+ "valid": True,
+ "peer": {
+ "hostname": "r1",
+ "type": "external",
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge_external,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see automatic eBGP peering"
+
+ def _bgp_converge_external_unnumbered():
+ output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aspath": {
+ "string": "65001",
+ },
+ "valid": True,
+ "peer": {
+ "hostname": "r1",
+ "type": "external",
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge_external_unnumbered,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see automatic unnumbered eBGP peering"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index 8b6fb98612..a574f43d89 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -679,6 +679,9 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
)
database_json = json.loads(isis_database_output)
+ if "lsps" not in database_json["areas"][0]["levels"][1]:
+ return "The LSP of {} has not been synchronized yet ".format(router.name)
+
att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"]
if att_p_ol == att_p_ol_expected:
return True
diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py
index be3241fd20..19f02dbadc 100644
--- a/tests/topotests/lib/common_check.py
+++ b/tests/topotests/lib/common_check.py
@@ -10,11 +10,13 @@ import json
from lib import topotest
-def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None):
+def ip_check_path_selection(
+ router, ipaddr_str, expected, vrf_name=None, check_fib=False
+):
if vrf_name:
- cmdstr = f'show ip route vrf {vrf_name} {ipaddr_str} json'
+ cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json"
else:
- cmdstr = f'show ip route {ipaddr_str} json'
+ cmdstr = f"show ip route {ipaddr_str} json"
try:
output = json.loads(router.vtysh_cmd(cmdstr))
except:
@@ -25,6 +27,21 @@ def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None):
num_nh_expected = len(expected[ipaddr_str][0]["nexthops"])
num_nh_observed = len(output[ipaddr_str][0]["nexthops"])
if num_nh_expected == num_nh_observed:
+ if check_fib:
+ # special case: when fib flag is unset,
+ # an extra test should be done to check that the flag is really unset
+ for nh_output, nh_expected in zip(
+ output[ipaddr_str][0]["nexthops"],
+ expected[ipaddr_str][0]["nexthops"],
+ ):
+ if (
+ "fib" in nh_output.keys()
+ and nh_output["fib"]
+ and ("fib" not in nh_expected.keys() or not nh_expected["fib"])
+ ):
+ return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format(
+ router.name, ipaddr_str, nh_output["ip"]
+ )
return ret
return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format(
router.name, ipaddr_str, num_nh_observed, num_nh_expected
@@ -37,9 +54,9 @@ def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None):
return None
if vrf_name:
- cmdstr = f'ip -json route show vrf {vrf_name} {ipaddr_str}'
+ cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}"
else:
- cmdstr = f'ip -json route show {ipaddr_str}'
+ cmdstr = f"ip -json route show {ipaddr_str}"
try:
output = json.loads(cmdstr)
except:
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index 26d56acc03..c875a6ec7f 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -360,16 +360,16 @@ module frr-route-map {
case set-min-metric {
when "derived-from-or-self(../action, 'set-min-metric')";
- choice minimun-metric-value {
+ choice minimum-metric-value {
description
- "Mimimum metric to set or use";
+ "Minimum metric to set or use";
case min-metric {
leaf min-metric {
type uint32 {
range "0..4294967295";
}
description
- "Use the following mimumn metric value";
+ "Use the following minimum metric value";
}
}
}
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 7910559c4b..0844b34672 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -4315,6 +4315,10 @@ dplane_route_update_internal(struct route_node *rn,
continue;
if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_DUPLICATE))
+ continue;
+
+ if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_ACTIVE))
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_FIB);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index b176ea2fe6..142f83fb36 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1659,6 +1659,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg,
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
continue;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ continue;
+
/* Check for a FIB nexthop corresponding to the RIB nexthop */
if (!nexthop_same(ctx_nexthop, nexthop)) {
/* If the FIB doesn't know about the nexthop,