diff options
65 files changed, 990 insertions, 265 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 34422bf514..4a5b0ba066 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2138,6 +2138,15 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; const bgp_size_t length = args->length; + /* if the ORIGINATOR_ID attribute is received from an external + * neighbor, it SHALL be discarded using the approach of "attribute + * discard". + */ + if (peer->sort == BGP_PEER_EBGP) { + stream_forward_getp(peer->curr, length); + return BGP_ATTR_PARSE_PROCEED; + } + /* if received from an internal neighbor, it SHALL be considered * malformed if its length is not equal to 4. If malformed, the * UPDATE message SHALL be handled using the approach of "treat-as- @@ -2174,6 +2183,15 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; const bgp_size_t length = args->length; + /* if the CLUSTER_LIST attribute is received from an external + * neighbor, it SHALL be discarded using the approach of "attribute + * discard". + */ + if (peer->sort == BGP_PEER_EBGP) { + stream_forward_getp(peer->curr, length); + return BGP_ATTR_PARSE_PROCEED; + } + /* if received from an internal neighbor, it SHALL be considered * malformed if its length is not a non-zero multiple of 4. If * malformed, the UPDATE message SHALL be handled using the approach @@ -2658,7 +2676,9 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ if (BGP_ATTR_ENCAP == type) { subtype = stream_getc(BGP_INPUT(peer)); - sublength = stream_getc(BGP_INPUT(peer)); + sublength = (subtype < 128) + ? stream_getc(BGP_INPUT(peer)) + : stream_getw(BGP_INPUT(peer)); length -= 2; #ifdef ENABLE_BGP_VNC } else { diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 625b7e59dc..a33f59cf5b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -936,7 +936,10 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, esi); - return zclient_send_message(zclient); + if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) + return -1; + + return 0; } /* @@ -988,7 +991,10 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); - return zclient_send_message(zclient); + if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) + return -1; + + return 0; } /* diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 4e8894cb44..2cea9971e6 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2258,12 +2258,6 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) peer, afi, safi, ORF_TYPE_PREFIX, REFRESH_IMMEDIATE, 0, BGP_ROUTE_REFRESH_NORMAL); - else if (CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) - bgp_route_refresh_send( - peer, afi, safi, ORF_TYPE_PREFIX_OLD, - REFRESH_IMMEDIATE, 0, - BGP_ROUTE_REFRESH_NORMAL); } } @@ -2272,9 +2266,7 @@ static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)) if (CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) + PEER_CAP_ORF_PREFIX_SM_RCV)) SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 84f770f7db..1b266314fb 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -36,7 +36,6 @@ static const struct message capcode_str[] = { {CAPABILITY_CODE_ADDPATH, "AddPath"}, {CAPABILITY_CODE_DYNAMIC, "Dynamic"}, {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"}, - {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"}, {CAPABILITY_CODE_FQDN, "FQDN"}, {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, @@ -55,7 +54,6 @@ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, - [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, @@ -78,7 +76,6 @@ static const size_t cap_modsizes[] = { [CAPABILITY_CODE_ADDPATH] = 4, [CAPABILITY_CODE_DYNAMIC] = 1, [CAPABILITY_CODE_ENHE] = 6, - [CAPABILITY_CODE_ORF_OLD] = 1, [CAPABILITY_CODE_FQDN] = 1, [CAPABILITY_CODE_ENHANCED_RR] = 1, [CAPABILITY_CODE_EXT_MESSAGE] = 1, @@ -345,7 +342,6 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi, static const struct message orf_type_str[] = { {ORF_TYPE_RESERVED, "Reserved"}, {ORF_TYPE_PREFIX, "Prefixlist"}, - {ORF_TYPE_PREFIX_OLD, "Prefixlist (old)"}, {0}}; static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"}, @@ -434,22 +430,6 @@ static int bgp_capability_orf_entry(struct peer *peer, continue; } break; - case CAPABILITY_CODE_ORF_OLD: - switch (type) { - case ORF_TYPE_RESERVED: - if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Addr-family %d/%d has reserved ORF type, ignoring", - peer->host, afi, safi); - break; - case ORF_TYPE_PREFIX_OLD: - break; - default: - bgp_capability_orf_not_support( - peer, pkt_afi, pkt_safi, type, mode); - continue; - } - break; default: bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, type, mode); @@ -476,9 +456,6 @@ static int bgp_capability_orf_entry(struct peer *peer, if (hdr->code == CAPABILITY_CODE_ORF) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; - } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { - sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; - rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; } else { bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, type, mode); @@ -1006,7 +983,6 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_MP: case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_ADDPATH: @@ -1076,7 +1052,6 @@ static int bgp_capability_parse(struct peer *peer, size_t length, SET_FLAG(peer->cap, PEER_CAP_REFRESH_RCV); } break; case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_ORF_OLD: ret = bgp_capability_orf_entry(peer, &caphdr); break; case CAPABILITY_CODE_RESTART: @@ -1486,9 +1461,7 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer, /* Address Prefix ORF */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { - stream_putc(s, (code == CAPABILITY_CODE_ORF - ? ORF_TYPE_PREFIX - : ORF_TYPE_PREFIX_OLD)); + stream_putc(s, ORF_TYPE_PREFIX); if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) @@ -1881,9 +1854,6 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { bgp_open_capability_orf(s, peer, afi, safi, - CAPABILITY_CODE_ORF_OLD, - ext_opt_params); - bgp_open_capability_orf(s, peer, afi, safi, CAPABILITY_CODE_ORF, ext_opt_params); } diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index c767100293..b18dbaa04f 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -38,7 +38,6 @@ struct graceful_restart_af { #define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */ #define CAPABILITY_CODE_SOFT_VERSION 75 /* Software Version capability */ #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ -#define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ #define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE 9 /* Role Capability */ @@ -63,7 +62,6 @@ struct graceful_restart_af { /* ORF Type */ #define ORF_TYPE_RESERVED 0 #define ORF_TYPE_PREFIX 64 -#define ORF_TYPE_PREFIX_OLD 128 /* ORF Mode */ #define ORF_MODE_RECEIVE 1 diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d30ba68347..ab9e940997 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1116,7 +1116,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, 0); stream_putc(s, pkt_safi); - if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) + if (orf_type == ORF_TYPE_PREFIX) if (remove || filter->plist[FILTER_IN].plist) { uint16_t orf_len; unsigned long orfp; @@ -2375,8 +2375,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) /* orf_len in bounds? */ if ((stream_pnt(s) + orf_len) > end) break; /* XXX: Notify instead?? */ - if (orf_type == ORF_TYPE_PREFIX - || orf_type == ORF_TYPE_PREFIX_OLD) { + if (orf_type == ORF_TYPE_PREFIX) { uint8_t *p_pnt = stream_pnt(s); uint8_t *p_end = stream_pnt(s) + orf_len; struct orf_prefix orfp; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0b821acfae..24be160656 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2181,10 +2181,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } /* ORF prefix-list filter check */ - if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) - && (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) + if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) && + CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)) if (peer->orf_plist[afi][safi]) { if (prefix_list_apply(peer->orf_plist[afi][safi], p) == PREFIX_DENY) { diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 0fe6180bea..849f669932 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -420,8 +420,6 @@ static unsigned int updgrp_hash_key_make(const void *p) */ if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL) || CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)) key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2), key); @@ -492,15 +490,12 @@ static unsigned int updgrp_hash_key_make(const void *p) : "(NONE)", peer->shared_network && peer_afi_active_nego(peer, AFI_IP6)); - zlog_debug( - "%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u ORF old: %u max prefix out: %ju", - peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL), - CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_RCV), - CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV), - (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_MAX_PREFIX_OUT)); + zlog_debug("%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u max prefix out: %ju", + peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL), + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_RCV), + (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_OUT)); zlog_debug( "%pBP Update Group Hash: local role: %u AIGP: %d SOO: %s", peer, peer->local_role, @@ -637,11 +632,9 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) if ((afi == AFI_IP6) && (pe1->shared_network != pe2->shared_network)) return false; - if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL) - || CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(pe1->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) - && !sockunion_same(&pe1->su, &pe2->su)) + if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL) || + CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)) && + !sockunion_same(&pe1->su, &pe2->su)) return false; return true; diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 67c384ba02..70e7ac30b5 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -55,9 +55,8 @@ #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV) #define PEER_UPDGRP_AF_CAP_FLAGS \ - (PEER_CAP_ORF_PREFIX_SM_RCV | PEER_CAP_ORF_PREFIX_SM_OLD_RCV \ - | PEER_CAP_ADDPATH_AF_TX_ADV | PEER_CAP_ADDPATH_AF_RX_RCV \ - | PEER_CAP_ENHE_AF_NEGO) + (PEER_CAP_ORF_PREFIX_SM_RCV | PEER_CAP_ADDPATH_AF_TX_ADV | \ + PEER_CAP_ADDPATH_AF_RX_RCV | PEER_CAP_ENHE_AF_NEGO) enum bpacket_attr_vec_type { BGP_ATTR_VEC_NH = 0, BGP_ATTR_VEC_MAX }; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cf74919e97..7942797528 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11854,7 +11854,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, &peer->ibuf->count, memory_order_relaxed); - vty_out(vty, "4 "); + vty_out(vty, "4"); vty_out(vty, ASN_FORMAT_SPACE(bgp->asnotation), &peer->as); if (show_wide) @@ -11930,14 +11930,23 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, } /* Make sure `Desc` column is the lastest in * the output. + * If the description is not set, try + * to print the software version if the + * capability is enabled and received. */ if (peer->desc) vty_out(vty, " %s", bgp_peer_description_stripped( peer->desc, show_wide ? 64 : 20)); - else + else if (peer->soft_version) { + vty_out(vty, " %s", + bgp_peer_description_stripped( + peer->soft_version, + show_wide ? 64 : 20)); + } else { vty_out(vty, " N/A"); + } vty_out(vty, "\n"); } @@ -12659,7 +12668,6 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, int orf_pfx_count; json_object *json_af = NULL; json_object *json_prefA = NULL; - json_object *json_prefB = NULL; json_object *json_addr = NULL; json_object *json_advmap = NULL; @@ -12702,37 +12710,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, json_prefA); } - if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) { - json_object_int_add(json_af, "orfOldType", - ORF_TYPE_PREFIX_OLD); - json_prefB = json_object_new_object(); - bgp_show_peer_afi_orf_cap( - vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV, - PEER_CAP_ORF_PREFIX_RM_ADV, - PEER_CAP_ORF_PREFIX_SM_OLD_RCV, - PEER_CAP_ORF_PREFIX_RM_OLD_RCV, use_json, - json_prefB); - json_object_object_add(json_af, "orfOldPrefixList", - json_prefB); - } - - if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_RCV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) json_object_object_add(json_addr, "afDependentCap", json_af); else @@ -13019,17 +13003,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, } else { vty_out(vty, " Not part of any update group\n"); } - if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_RCV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) vty_out(vty, " AF-dependant capabilities:\n"); if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) @@ -13048,22 +13028,6 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, PEER_CAP_ORF_PREFIX_SM_RCV, PEER_CAP_ORF_PREFIX_RM_RCV, use_json, NULL); } - if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_OLD_RCV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_ADV) - || CHECK_FLAG(p->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) { - vty_out(vty, - " Outbound Route Filter (ORF) type (%d) Prefix-list:\n", - ORF_TYPE_PREFIX_OLD); - bgp_show_peer_afi_orf_cap( - vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV, - PEER_CAP_ORF_PREFIX_RM_ADV, - PEER_CAP_ORF_PREFIX_SM_OLD_RCV, - PEER_CAP_ORF_PREFIX_RM_OLD_RCV, use_json, NULL); - } snprintf(orf_pfx_name, sizeof(orf_pfx_name), "%s.%d.%d", p->host, afi, safi); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 430ea0f9a2..1320906339 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1085,7 +1085,7 @@ static void bgp_zebra_tm_connect(struct event *t) } bgp_tm_status_connected = true; if (!bgp_tm_chunk_obtained) { - if (bgp_zebra_get_table_range(bgp_tm_chunk_size, + if (bgp_zebra_get_table_range(zclient, bgp_tm_chunk_size, &bgp_tm_min, &bgp_tm_max) >= 0) { bgp_tm_chunk_obtained = true; @@ -1129,14 +1129,14 @@ void bgp_zebra_init_tm_connect(struct bgp *bgp) &bgp_tm_thread_connect); } -int bgp_zebra_get_table_range(uint32_t chunk_size, +int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, uint32_t *start, uint32_t *end) { int ret; if (!bgp_tm_status_connected) return -1; - ret = tm_get_table_chunk(zclient, chunk_size, start, end); + ret = tm_get_table_chunk(zc, chunk_size, start, end); if (ret < 0) { flog_err(EC_BGP_TABLE_CHUNK, "BGP: Error getting table chunk %u", chunk_size); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 3d7d71d9b4..a0f7819460 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -24,7 +24,7 @@ extern void bgp_zebra_init_tm_connect(struct bgp *bgp); extern uint32_t bgp_zebra_tm_get_id(void); extern bool bgp_zebra_tm_chunk_obtained(void); extern void bgp_zebra_destroy(void); -extern int bgp_zebra_get_table_range(uint32_t chunk_size, +extern int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int bgp_if_update_all(void); extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5544c59df8..5c97f90c55 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6964,11 +6964,8 @@ static void peer_prefix_list_update(struct prefix_list *plist) */ if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) && - (CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_RCV) || - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_RCV)) peer_clear_soft( peer, afi, safi, BGP_CLEAR_SOFT_IN_ORF_PREFIX); @@ -7935,19 +7932,15 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) { if (CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_SM_ADV) - && (CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_RCV) - || CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) { + PEER_CAP_ORF_PREFIX_SM_ADV) && + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_RCV)) { struct bgp_filter *filter = &peer->filter[afi][safi]; uint8_t prefix_type; if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) prefix_type = ORF_TYPE_PREFIX; - else - prefix_type = ORF_TYPE_PREFIX_OLD; if (filter->plist[FILTER_IN].plist) { if (CHECK_FLAG(peer->af_sflags[afi][safi], diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index b8208cecee..edf9234424 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1280,8 +1280,6 @@ struct peer { #define PEER_CAP_ORF_PREFIX_RM_ADV (1U << 1) /* receive-mode advertised */ #define PEER_CAP_ORF_PREFIX_SM_RCV (1U << 2) /* send-mode received */ #define PEER_CAP_ORF_PREFIX_RM_RCV (1U << 3) /* receive-mode received */ -#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1U << 4) /* send-mode received */ -#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1U << 5) /* receive-mode received */ #define PEER_CAP_RESTART_AF_RCV (1U << 6) /* graceful restart afi/safi received */ #define PEER_CAP_RESTART_AF_PRESERVE_RCV (1U << 7) /* graceful restart afi/safi F-bit received */ #define PEER_CAP_ADDPATH_AF_TX_ADV (1U << 8) /* addpath tx advertised */ diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 3430d8a282..232b1c3934 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -912,7 +912,7 @@ Opaque LSA - *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for + *ospfd* supports Opaque LSA (:rfc:`5250`) as partial support for MPLS Traffic Engineering LSAs. The opaque-lsa capability must be enabled in the configuration. An alternate command could be "mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR @@ -920,6 +920,18 @@ Opaque LSA extensions that are used with MPLS-TE; it does not support a complete RSVP-TE solution. +.. clicmd:: ip ospf capability opaque [A.B.C.D] + + Enable or disable OSPF LSA database exchange and flooding on an interface. + The default is that opaque capability is enabled as long as the opaque + capability is enabled with the :clicmd:`capability opaque` command at the + OSPF instance level (using the command above). Note that disabling opaque + LSA support on an interface will impact the applications using opaque LSAs + if the opaque LSAs are not received on other flooding paths by all the + OSPF routers using those applications. For example, OSPF Graceful Restart + uses opaque-link LSAs and disabling support on an interface will disable + graceful restart signaling on that interface. + .. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) .. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 09ffa3479a..e4ef6c8dfa 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -474,20 +474,20 @@ void log_multiline(int priority, const char *prefix, const char *format, ...) char *log_uptime(time_t uptime, char *buf, size_t nbuf) { - struct tm *tm; + struct tm tm; time_t difftime = time(NULL); difftime -= uptime; - tm = gmtime(&difftime); + gmtime_r(&difftime, &tm); if (difftime < ONE_DAY_SECOND) - snprintf(buf, nbuf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, - tm->tm_sec); + snprintf(buf, nbuf, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, + tm.tm_sec); else if (difftime < ONE_WEEK_SECOND) - snprintf(buf, nbuf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, - tm->tm_min); + snprintf(buf, nbuf, "%dd%02dh%02dm", tm.tm_yday, tm.tm_hour, + tm.tm_min); else - snprintf(buf, nbuf, "%02dw%dd%02dh", tm->tm_yday / 7, - tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour); + snprintf(buf, nbuf, "%02dw%dd%02dh", tm.tm_yday / 7, + tm.tm_yday - ((tm.tm_yday / 7) * 7), tm.tm_hour); return buf; } @@ -66,10 +66,10 @@ extern char *asn_asn2string(const as_t *as, char *buf, size_t len, ((mode == ASNOTATION_DOT) ? "%pASD" : \ ((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \ "%pASP")) -#define ASN_FORMAT_SPACE(mode) \ - ((mode == ASNOTATION_DOT) ? "%10pASD" : \ - ((mode == ASNOTATION_DOTPLUS) ? "%10pASE" : \ - "%10pASP")) +#define ASN_FORMAT_SPACE(mode) \ + ((mode == ASNOTATION_DOT) \ + ? "%11pASD" \ + : ((mode == ASNOTATION_DOTPLUS) ? "%11pASE" : "%11pASP")) /* for test */ extern void asn_relax_as_zero(bool relax); diff --git a/lib/libospf.h b/lib/libospf.h index 9eaca9a1a8..e3c1adb810 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -69,6 +69,7 @@ extern "C" { #define OSPF_MTU_IGNORE_DEFAULT 0 #define OSPF_FAST_HELLO_DEFAULT 0 #define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false +#define OSPF_OPAQUE_CAPABLE_DEFAULT true #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ #define OSPF_AREA_RANGE_COST_UNSPEC -1U diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index bf7ba5f650..060e60314d 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -108,11 +108,10 @@ void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, - const union sockunion *nexthop, uint32_t mtu) + const union sockunion *nexthop_ref, uint32_t mtu) { struct zapi_route api; struct zapi_nexthop *api_nh; - union sockunion *nexthop_ref = (union sockunion *)nexthop; if (zclient->sock < 0) return; @@ -125,9 +124,10 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, switch (type) { case NHRP_CACHE_NEGATIVE: + /* Fill in a blackhole nexthop */ zapi_route_set_blackhole(&api, BLACKHOLE_REJECT); ifp = NULL; - nexthop = NULL; + nexthop_ref = NULL; break; case NHRP_CACHE_DYNAMIC: case NHRP_CACHE_NHS: diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 5ae15fd887..dd8c9268f1 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -568,6 +568,15 @@ int ospf_flood_through_interface(struct ospf_interface *oi, if (!ospf_if_is_enable(oi)) return 0; + if (IS_OPAQUE_LSA(lsa->data->type) && + !OSPF_IF_PARAM(oi, opaque_capable)) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug( + "%s: Skipping interface %s (%s) with opaque disabled.", + __func__, IF_NAME(oi), ospf_get_name(oi->ospf)); + return 0; + } + /* If flood reduction is configured, set the DC bit on the lsa. */ if (IS_LSA_SELF(lsa)) { if (OSPF_FR_CONFIG(oi->area->ospf, oi->area)) { diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index 2a346f2388..c23c42052f 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -773,8 +773,15 @@ static void ospf_gr_prepare(void) } /* Send a Grace-LSA to all neighbors. */ - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) - ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, false); + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) { + if (OSPF_IF_PARAM(oi, opaque_capable)) + ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, + false); + else + zlog_debug( + "GR: skipping grace LSA on interface %s (%s) with opaque capability disabled", + IF_NAME(oi), ospf_get_name(oi->ospf)); + } /* Record end of the grace period in non-volatile memory. */ ospf_gr_nvm_update(ospf, true); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 9e6acdbf0d..72de198116 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -271,6 +271,10 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, QOBJ_REG(oi, ospf_interface); + /* If first oi, check per-intf write socket */ + if (ospf->oi_running && ospf->intf_socket_enabled) + ospf_ifp_sock_init(ifp); + if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u created", __func__, ifp->name, ospf_get_name(ospf), @@ -327,6 +331,8 @@ void ospf_if_cleanup(struct ospf_interface *oi) void ospf_if_free(struct ospf_interface *oi) { + struct interface *ifp = oi->ifp; + ospf_if_down(oi); ospf_fifo_free(oi->obuf); @@ -361,6 +367,10 @@ void ospf_if_free(struct ospf_interface *oi) event_cancel_event(master, oi); + /* If last oi, close per-interface socket */ + if (ospf_oi_count(ifp) == 0) + ospf_ifp_sock_close(ifp); + memset(oi, 0, sizeof(*oi)); XFREE(MTYPE_OSPF_IF, oi); } @@ -538,6 +548,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, auth_crypt); UNSET_IF_PARAM(oip, auth_type); UNSET_IF_PARAM(oip, if_area); + UNSET_IF_PARAM(oip, opaque_capable); oip->auth_crypt = list_new(); @@ -546,6 +557,7 @@ static struct ospf_if_params *ospf_new_if_params(void) oip->ptp_dmvpn = 0; oip->p2mp_delay_reflood = OSPF_P2MP_DELAY_REFLOOD_DEFAULT; + oip->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT; return oip; } @@ -575,19 +587,20 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) oip = rn->info; route_unlock_node(rn); - if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) - && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) - && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) - && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) - && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) - && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) - && !OSPF_IF_PARAM_CONFIGURED(oip, v_wait) - && !OSPF_IF_PARAM_CONFIGURED(oip, priority) - && !OSPF_IF_PARAM_CONFIGURED(oip, type) - && !OSPF_IF_PARAM_CONFIGURED(oip, auth_simple) - && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) - && !OSPF_IF_PARAM_CONFIGURED(oip, if_area) - && listcount(oip->auth_crypt) == 0) { + if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && + !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && + !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && + !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && + !OSPF_IF_PARAM_CONFIGURED(oip, v_wait) && + !OSPF_IF_PARAM_CONFIGURED(oip, priority) && + !OSPF_IF_PARAM_CONFIGURED(oip, type) && + !OSPF_IF_PARAM_CONFIGURED(oip, auth_simple) && + !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) && + !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && + !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) && + listcount(oip->auth_crypt) == 0) { ospf_del_if_params(ifp, oip); rn->info = NULL; route_unlock_node(rn); @@ -693,6 +706,9 @@ int ospf_if_new_hook(struct interface *ifp) SET_IF_PARAM(IF_DEF_PARAMS(ifp), auth_type); IF_DEF_PARAMS(ifp)->auth_type = OSPF_AUTH_NOTSET; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable); + IF_DEF_PARAMS(ifp)->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT; + rc = ospf_opaque_new_if(ifp); return rc; } @@ -1404,7 +1420,8 @@ static int ospf_ifp_up(struct interface *ifp) /* Open per-intf write socket if configured */ ospf = ifp->vrf->info; - if (ospf && ospf->intf_socket_enabled) + + if (ospf && ospf->oi_running && ospf->intf_socket_enabled) ospf_ifp_sock_init(ifp); ospf_if_recalculate_output_cost(ifp); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index ec1afa1b8b..38ec45c757 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -112,6 +112,9 @@ struct ospf_if_params { /* point-to-multipoint delayed reflooding configuration */ bool p2mp_delay_reflood; + + /* Opaque LSA capability at interface level (see RFC5250) */ + DECLARE_IF_PARAM(bool, opaque_capable); }; enum { MEMBER_ALLROUTERS = 0, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 67f1faf8a9..27e7e02759 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2007,7 +2007,6 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf, /* add translated flag, checksum and lock new lsa */ SET_FLAG(new->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ - new = ospf_lsa_lock(new); return new; } diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index aff8ed05c7..801f75ad18 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -159,7 +159,8 @@ int ospf_if_ipmulticast(int fd, struct prefix *p, ifindex_t ifindex) * Helper to open and set up a socket; returns the new fd on success, * -1 on error. */ -static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd) +static int sock_init_common(vrf_id_t vrf_id, const char *name, int proto, + int *pfd) { int ospf_sock; int ret, hincl = 1; @@ -170,8 +171,7 @@ static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd) } frr_with_privs(&ospfd_privs) { - ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP, - vrf_id, name); + ospf_sock = vrf_socket(AF_INET, SOCK_RAW, proto, vrf_id, name); if (ospf_sock < 0) { flog_err(EC_LIB_SOCKET, "%s: socket: %s", __func__, safe_strerror(errno)); @@ -244,7 +244,8 @@ int ospf_sock_init(struct ospf *ospf) if (ospf->fd > 0) return -1; - ret = sock_init_common(ospf->vrf_id, ospf->name, &(ospf->fd)); + ret = sock_init_common(ospf->vrf_id, ospf->name, IPPROTO_OSPFIGP, + &(ospf->fd)); if (ret >= 0) /* Update socket buffer sizes */ ospf_sock_bufsize_update(ospf, ospf->fd, OSPF_SOCK_BOTH); @@ -258,8 +259,8 @@ int ospf_sock_init(struct ospf *ospf) int ospf_ifp_sock_init(struct interface *ifp) { struct ospf_if_info *oii; - struct ospf_interface *oi; - struct ospf *ospf; + struct ospf_interface *oi = NULL; + struct ospf *ospf = NULL; struct route_node *rn; int ret; @@ -270,17 +271,26 @@ int ospf_ifp_sock_init(struct interface *ifp) if (oii->oii_fd > 0) return 0; - rn = route_top(IF_OIFS(ifp)); - if (rn && rn->info) { - oi = rn->info; - ospf = oi->ospf; - } else + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + if (rn && rn->info) { + oi = rn->info; + ospf = oi->ospf; + break; + } + } + + if (ospf == NULL) return -1; - ret = sock_init_common(ifp->vrf->vrf_id, ifp->name, &oii->oii_fd); + ret = sock_init_common(ifp->vrf->vrf_id, ifp->name, IPPROTO_OSPFIGP, + &oii->oii_fd); - if (ret >= 0) /* Update socket buffer sizes */ - ospf_sock_bufsize_update(ospf, oii->oii_fd, OSPF_SOCK_BOTH); + if (ret >= 0) { /* Update socket buffer sizes */ + /* Write-only, so no recv buf */ + setsockopt_so_recvbuf(oii->oii_fd, 0); + + ospf_sock_bufsize_update(ospf, oii->oii_fd, OSPF_SOCK_SEND); + } if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ifp %s, oii %p, fd %d", __func__, ifp->name, diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 6894c6a009..27f47a6d79 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1851,9 +1851,9 @@ static void ospf_opaque_type9_lsa_reoriginate_timer(struct event *t) return; } - if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) - || !ospf_if_is_enable(oi) - || ospf_nbr_count_opaque_capable(oi) == 0) { + if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) || + !OSPF_IF_PARAM(oi, opaque_capable) || !ospf_if_is_enable(oi) || + ospf_nbr_count_opaque_capable(oi) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 105c04c7a1..cfa0d5d574 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -953,8 +953,9 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) - && CHECK_FLAG(hello->options, OSPF_OPTION_O)) { + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable) && + CHECK_FLAG(hello->options, OSPF_OPTION_O)) { /* * This router does know the correct usage of O-bit * the bit should be set in DD packet only. @@ -1362,8 +1363,9 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ - if (CHECK_FLAG(dd->options, OSPF_OPTION_O) - && !CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { + if (CHECK_FLAG(dd->options, OSPF_OPTION_O) && + (!CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) || + !OSPF_IF_PARAM(oi, opaque_capable))) { /* * This node is not configured to handle O-bit, for now. * Clear it to ignore unsupported capability proposed by @@ -1448,7 +1450,8 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, /* This is where the real Options are saved */ nbr->options = dd->options; - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "Neighbor[%pI4] is %sOpaque-capable.", @@ -3435,7 +3438,8 @@ static int ospf_make_db_desc(struct ospf_interface *oi, /* Set Options. */ options = OPTIONS(oi); - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable)) SET_FLAG(options, OSPF_OPTION_O); if (OSPF_FR_CONFIG(oi->ospf, oi->area)) SET_FLAG(options, OSPF_OPTION_DC); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 863055bf42..54fd60af23 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3811,6 +3811,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, lookup_msg(ospf_ism_state_msg, oi->state, NULL)); json_object_int_add(json_oi, "priority", PRIORITY(oi)); + json_object_boolean_add( + json_interface_sub, "opaqueCapable", + OSPF_IF_PARAM(oi, opaque_capable)); } else { vty_out(vty, " Area %s\n", ospf_area_desc_string(oi->area)); @@ -3830,6 +3833,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, OSPF_IF_PARAM(oi, transmit_delay), lookup_msg(ospf_ism_state_msg, oi->state, NULL), PRIORITY(oi)); + if (!OSPF_IF_PARAM(oi, opaque_capable)) + vty_out(vty, + " Opaque LSA capability disabled on interface\n"); } /* Show DR information. */ @@ -9803,6 +9809,61 @@ DEFUN (no_ip_ospf_mtu_ignore, return CMD_SUCCESS; } +DEFPY(ip_ospf_capability_opaque, ip_ospf_capability_opaque_addr_cmd, + "[no] ip ospf capability opaque [A.B.C.D]$ip_addr", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Disable OSPF capability on this interface\n" + "Disable OSPF opaque LSA capability on this interface\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct route_node *rn; + bool old_opaque_capable; + bool opaque_capable_change; + + struct ospf_if_params *params; + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + old_opaque_capable = params->opaque_capable; + params->opaque_capable = (no) ? false : true; + opaque_capable_change = (old_opaque_capable != params->opaque_capable); + if (params->opaque_capable != OSPF_OPAQUE_CAPABLE_DEFAULT) + SET_IF_PARAM(params, opaque_capable); + else { + UNSET_IF_PARAM(params, opaque_capable); + if (params != IF_DEF_PARAMS(ifp)) { + ospf_free_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + } + + /* + * If there is a change to the opaque capability, flap the interface + * to reset all the neighbor adjacencies. + */ + if (opaque_capable_change) { + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + struct ospf_interface *oi = rn->info; + + if (oi && (oi->state > ISM_Down) && + (ip_addr.s_addr == INADDR_ANY || + IPV4_ADDR_SAME(&oi->address->u.prefix4, + &ip_addr))) { + OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceUp); + } + } + } + return CMD_SUCCESS; +} + DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, @@ -12167,6 +12228,21 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) if (params && params->ldp_sync_info) ospf_ldp_sync_if_write_config(vty, params); + /* Capability opaque print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, opaque_capable) && + params->opaque_capable != + OSPF_OPAQUE_CAPABLE_DEFAULT) { + if (params->opaque_capable == false) + vty_out(vty, + " no ip ospf capability opaque"); + else + vty_out(vty, + " ip ospf capability opaque"); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + while (1) { if (rn == NULL) rn = route_top(IF_OIFS_PARAMS(ifp)); @@ -12976,6 +13052,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &ip_ospf_passive_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_passive_cmd); + /* "ip ospf capability opaque" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_capability_opaque_addr_cmd); + /* These commands are compatibitliy for previous version. */ install_element(INTERFACE_NODE, &ospf_authentication_key_cmd); install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd); diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 6af19cadd7..716cb8db5b 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -2844,6 +2844,8 @@ static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet, json_object *json_row = NULL; json_object *json_ifp = NULL; json_object *json_arr = NULL; + struct pim_interface *pim_ifp = NULL; + bool pim_enable = false; for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) { first_ifindex = nh_node->ifindex; @@ -2863,6 +2865,14 @@ static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet, json_ifp = json_object_new_object(); json_object_string_add(json_ifp, "interface", ifp ? ifp->name : "NULL"); + + if (ifp) + pim_ifp = ifp->info; + + if (pim_ifp && pim_ifp->pim_enable) + pim_enable = true; + + json_object_boolean_add(json_ifp, "pimEnabled", pim_enable); #if PIM_IPV == 4 json_object_string_addf(json_ifp, "nexthop", "%pI4", &nh_node->gate.ipv4); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 3a2a7aa407..f0a75a5fc2 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -179,7 +179,7 @@ DEFPY (install_routes, <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\ nexthop-group NHGNAME$nexthop_group>\ [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \ - (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]", + (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD] [no-recurse$norecurse]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" @@ -201,7 +201,8 @@ DEFPY (install_routes, "Should we repeat this command\n" "How many times to repeat this command\n" "What opaque data to send down\n" - "The opaque data\n") + "The opaque data\n" + "No recursive nexthops\n") { struct vrf *vrf; struct prefix prefix; @@ -210,6 +211,7 @@ DEFPY (install_routes, sg.r.total_routes = routes; sg.r.installed_routes = 0; + sg.r.flags = 0; if (rpt >= 2) sg.r.repeat = rpt * 2; @@ -317,12 +319,16 @@ DEFPY (install_routes, else sg.r.opaque[0] = '\0'; + /* Default is to ask for recursive nexthop resolution */ + if (norecurse == NULL) + SET_FLAG(sg.r.flags, ZEBRA_FLAG_ALLOW_RECURSION); + sg.r.inst = instance; sg.r.vrf_id = vrf->vrf_id; rts = routes; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - rts, 0, sg.r.opaque); + rts, sg.r.flags, sg.r.opaque); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index df18118b02..c095fec17b 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,7 +247,6 @@ 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.flags, ZEBRA_FLAG_ALLOW_RECURSION); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ diff --git a/tests/.gitignore b/tests/.gitignore index f00177abd8..681438f4a5 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -29,6 +29,7 @@ frr_northbound* /lib/test_buffer /lib/test_checksum /lib/test_frrscript +/lib/test_darr /lib/test_frrlua /lib/test_graph /lib/test_grpc diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index e033a0f005..43f4905d41 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -1063,7 +1063,7 @@ def test_bgp_delayopen_dual(): delay_stop = int(time.time()) assertmsg = "BGP peering between r2 and r5 was established before DelayOpenTimer (30sec) on r2 could expire" - assert (delay_stop - delay_start) > 30, assertmsg + assert (delay_stop - delay_start) >= 30, assertmsg # 3.8 unset delayopen on R2 and R5 logger.info("Disabling DelayOpenTimer for neighbor r5 on r2") diff --git a/tests/topotests/bgp_flowspec/peer1/exabgp.cfg b/tests/topotests/bgp_flowspec/peer1/exabgp.cfg index cd1fae5aba..383a95b6dd 100644 --- a/tests/topotests/bgp_flowspec/peer1/exabgp.cfg +++ b/tests/topotests/bgp_flowspec/peer1/exabgp.cfg @@ -1,5 +1,6 @@ neighbor 10.0.1.1 { router-id 10.0.1.101; +hold-time 10; local-address 10.0.1.101; local-as 100; peer-as 100; diff --git a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py index b1bec1034b..a2be85962f 100644 --- a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py +++ b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py @@ -138,11 +138,12 @@ def test_bgp_convergence(): test_func = functools.partial( topotest.router_json_cmp, router, "show bgp summary json", expected ) - _, res = topotest.run_and_expect(test_func, None, count=90, wait=0.5) + _, res = topotest.run_and_expect(test_func, None, count=210, wait=1) assertmsg = "BGP router network did not converge" if res is not None: generate_support_bundle() assert res is None, assertmsg + generate_support_bundle() def test_bgp_flowspec(): diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf index 8d42cfc0d8..72211fee7f 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -5,7 +5,7 @@ password zebra log stdout notifications log commands -log file bgpd.log debugging +log file bgpd.log #debug bgp vpn leak-to-vrf #debug bgp vpn leak-from-vrf diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf index 7b42b770b5..edb3b699f9 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf @@ -4,7 +4,7 @@ hostname r2 password zebra log stdout notifications log commands -log file bgpd.log debugging +log file bgpd.log router bgp 5226 bgp router-id 2.2.2.2 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf index ca9e627172..ed76ed3c63 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf @@ -4,7 +4,7 @@ hostname r4 password zebra log stdout notifications log commands -log file bgpd.log debug +log file bgpd.log #debug bgp vpn label #debug bgp nht diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index ebaab60341..c97cd0bdda 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -83,7 +83,7 @@ def test_bgp_path_attribute_discard(): "paths": [ { "valid": True, - "originatorId": "10.0.0.2", + "originatorId": None, "community": { "string": "65001:102", }, @@ -98,12 +98,12 @@ def test_bgp_path_attribute_discard(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence" - step("Discard atomic-aggregate, community, and originator-id attributes from peer1") + step("Discard atomic-aggregate, and community attributes from peer1") r1.vtysh_cmd( """ configure terminal router bgp - neighbor 10.0.0.2 path-attribute discard 6 8 9 + neighbor 10.0.0.2 path-attribute discard 6 8 """ ) @@ -137,7 +137,7 @@ def test_bgp_path_attribute_discard(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None - ), "Failed to discard path attributes (atomic-aggregate, community, and originator-id)" + ), "Failed to discard path attributes (atomic-aggregate, community)" def test_memory_leak(): diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index 934c2ff16a..ce278ed7a7 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -242,6 +242,10 @@ def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=Non if label_list is not None: label_list.add(in_label) for nh in label_info["nexthops"]: + if "installed" not in nh.keys(): + return "{} {} is not installed yet on {}".format( + in_label, label_info, router.name + ) if nh["installed"] != True or nh["type"] != "BGP": return "{}, show mpls table, nexthop is not installed".format( router.name diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index cb25d63a36..f829ed2d12 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -297,6 +297,52 @@ def check_for_memleaks(): pytest.fail("memleaks found for daemons: " + " ".join(daemons)) +def check_for_core_dumps(): + dumps = [] + tgen = get_topogen() # pylint: disable=redefined-outer-name + latest = [] + + if tgen is not None: + logdir = tgen.logdir + cores = glob.glob(os.path.join(logdir, "*/*.dmp")) + + if cores: + logger.error("Cores found:\n\t%s", "\n\t".join(cores)) + pytest.fail("Core files found") + + +def check_for_backtraces(): + backtraces = [] + tgen = get_topogen() # pylint: disable=redefined-outer-name + latest = [] + existing = [] + if tgen is not None: + logdir = tgen.logdir + if hasattr(tgen, "backtraces_existing_files"): + existing = tgen.backtraces_existing_files + latest = glob.glob(os.path.join(logdir, "*/*.log")) + + daemons = [] + for vfile in latest: + if vfile in existing: + continue + with open(vfile, encoding="ascii") as vf: + vfcontent = vf.read() + backtrace = vfcontent.count("Backtrace:") + if backtrace: + existing.append(vfile) # have backtrace don't check again + emsg = "Backtrace found in {}, failing test".format(vfile) + backtraces.append(emsg) + + if tgen is not None: + tgen.backtrace_existing_files = existing + + if backtraces: + logger.error("Backtraces found in test suite, erroring") + logger.error(backtraces) + pytest.fail("Backtraces found") + + @pytest.fixture(autouse=True, scope="module") def module_autouse(request): basename = get_test_logdir(request.node.nodeid, True) @@ -320,6 +366,8 @@ def module_check_memtest(request): if request.config.option.memleaks: if get_topogen() is not None: check_for_memleaks() + check_for_backtraces() + check_for_core_dumps() # diff --git a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf index 955bd5caa0..620523512a 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf @@ -16,6 +16,7 @@ interface lo interface eth-sw1 ip router isis 1 ipv6 router isis 1 + isis hello-interval 1 isis hello-multiplier 3 isis priority 100 isis fast-reroute ti-lfa diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref index 26f0dffa7a..d86f9ef658 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref @@ -11,14 +11,14 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0003", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 64, "state": "up" }, { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0002", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 64, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf index f971c658d4..9c4b86208b 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf @@ -15,6 +15,7 @@ interface lo interface eth-sw1 ip router isis 1 ipv6 router isis 1 + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -22,6 +23,7 @@ interface eth-rt4-1 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -29,6 +31,7 @@ interface eth-rt4-2 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref index 1ea72a528b..69b6159d62 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref @@ -11,7 +11,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0004", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -30,7 +30,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0004", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -49,14 +49,14 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0001", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 100, "state": "up" }, { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0003", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 64, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf index 64f091cfed..1883575b7b 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf @@ -15,6 +15,7 @@ interface lo interface eth-sw1 ip router isis 1 ipv6 router isis 1 + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -22,6 +23,7 @@ interface eth-rt5-1 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -29,6 +31,7 @@ interface eth-rt5-2 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref index d174b4a475..e75d5fe859 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref @@ -11,7 +11,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0005", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -30,7 +30,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0005", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -49,14 +49,14 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0001", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 100, "state": "up" }, { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0002", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 64, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf index 9223852f79..94f80d39d5 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf @@ -16,6 +16,7 @@ interface eth-rt2-1 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -23,6 +24,7 @@ interface eth-rt2-2 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -30,6 +32,7 @@ interface eth-rt5 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -37,6 +40,7 @@ interface eth-rt6 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref index 2eb64b6fc9..1d2c559588 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref @@ -11,7 +11,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0002", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -30,7 +30,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0002", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -49,7 +49,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0005", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -68,7 +68,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0006", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf index a08534cf30..e83ae9677b 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf @@ -16,6 +16,7 @@ interface eth-rt3-1 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -23,6 +24,7 @@ interface eth-rt3-2 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -30,6 +32,7 @@ interface eth-rt4 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -37,6 +40,7 @@ interface eth-rt6 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref index 1ff8c2cd4e..f94b09e161 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref @@ -11,7 +11,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0003", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -30,7 +30,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0003", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -49,7 +49,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0004", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -68,7 +68,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0006", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf index d92f822b8d..462492e909 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf @@ -16,6 +16,7 @@ interface eth-rt4 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! @@ -23,6 +24,7 @@ interface eth-rt5 ip router isis 1 ipv6 router isis 1 isis network point-to-point + isis hello-interval 1 isis hello-multiplier 3 isis fast-reroute ti-lfa ! diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref index 734832358f..9d4d47b2af 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref @@ -11,7 +11,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0004", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } @@ -30,7 +30,7 @@ { "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0005", - "hold-timer": 9, + "hold-timer": 3, "neighbor-priority": 0, "state": "up" } diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index 1ed52ab76d..f0724b9da6 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -1021,7 +1021,8 @@ def test_rt6_step14(): rname, "show ipv6 route isis json", outputs[rname][11]["show_ipv6_route.ref"], - count=10, + count=20, + wait=2, ) router_compare_json_output( rname, diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 845d3e3b53..7371230057 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1189,8 +1189,8 @@ def rlimit_atleast(rname, min_value, raises=False): def fix_netns_limits(ns): # Maximum read and write socket buffer sizes - sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20]) - sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20]) + sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20]) + sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20]) sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0) sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0) @@ -1249,8 +1249,8 @@ def fix_host_limits(): sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024) # Maximum read and write socket buffer sizes - sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20) - sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20) + sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20) + sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20) # Garbage Collection Settings for ARP and Neighbors sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024) @@ -1642,8 +1642,6 @@ class Router(Node): # TODO remove the following lines after all tests are migrated to Topogen. # Try to find relevant old logfiles in /tmp and delete them map(os.remove, glob.glob("{}/{}/*.log".format(self.logdir, self.name))) - # Remove old core files - map(os.remove, glob.glob("{}/{}/*.dmp".format(self.logdir, self.name))) # Remove IP addresses from OS first - we have them in zebra.conf self.removeIPs() # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher diff --git a/tests/topotests/nhrp_topo/r1/sharp_route4.json b/tests/topotests/nhrp_topo/r1/sharp_route4.json new file mode 100644 index 0000000000..4c4b8eaccd --- /dev/null +++ b/tests/topotests/nhrp_topo/r1/sharp_route4.json @@ -0,0 +1,46 @@ +{ + "4.4.4.1\/32":[ + { + "prefix":"4.4.4.1\/32", + "prefixLen":32, + "protocol":"sharp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "ip":"10.255.255.2", + "interfaceName":"r1-gre0", + "active":true + } + ] + } + ], + "5.5.5.1\/32":[ + { + "prefix":"5.5.5.1\/32", + "prefixLen":32, + "protocol":"sharp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "ip":"10.255.255.2", + "interfaceName":"r1-gre0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 879f5250ec..78b82eda79 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -108,6 +108,12 @@ def setup_module(mod): TopoRouter.RD_NHRP, os.path.join(CWD, "{}/nhrpd.conf".format(rname)) ) + # Include sharpd for r1 + if rname == "r1": + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) + # Initialize all routers. logger.info("Launching NHRP") for name in router_list: @@ -201,6 +207,38 @@ def test_nhrp_connection(): logger.info("Check Ping IPv4 from R1 to R2 OK") +def test_route_install(): + "Test use of NHRP routes by other protocols (sharpd here)." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing route install over NHRP tunnel") + + # Install sharpd routes over an NHRP route + r1 = tgen.gears["r1"] + + # Install one recursive and one non-recursive sharpd route + r1.vtysh_cmd("sharp install route 4.4.4.1 nexthop 10.255.255.2 1") + + r1.vtysh_cmd("sharp install route 5.5.5.1 nexthop 10.255.255.2 1 no-recurse") + + json_file = "{}/{}/sharp_route4.json".format(CWD, "r1") + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route sharp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + + logger.info("Sharp routes:") + output = r1.vtysh_cmd("show ip route sharp") + logger.info(output) + + assertmsg = '"{}" JSON route output mismatches'.format(r1.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 39ebbcfb62..7a7ea85e2f 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -17,6 +17,7 @@ import subprocess import sys import time from datetime import datetime, timedelta +from functools import partial import pytest from lib.common_config import ( @@ -31,6 +32,12 @@ from lib.micronet import Timeout, comm_error from lib.topogen import Topogen, TopoRouter from lib.topotest import interface_set_status, json_cmp +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + pytestmark = [pytest.mark.ospfd] CWD = os.path.dirname(os.path.realpath(__file__)) @@ -1142,6 +1149,438 @@ def test_ospf_opaque_restart(tgen): _test_opaque_add_restart_add(tgen, apibin) +def _test_opaque_interface_disable(tgen, apibin): + "Test disabling opaque capability on an interface" + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + tc_name = "opaque_interface_disable" + + p = None + pread = None + # Log to our stdin, stderr + pout = open(os.path.join(r1.net.logdir, "r1/intf-disable.log"), "a+") + try: + # STEP 1 in test_ospf_opaque_interface_disable and STEP 56 in CI tests + step("Disable OSPF opaque LSA Copability on r1's interface to r2") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nno ip ospf capability opaque") + time.sleep(15) + + # STEP 2 in test_ospf_opaque_interface_disable and STEP 57 in CI tests + step("Verify the r1 configuration of 'no ip ospf capability opaque'") + no_capability_opaque_cfg = ( + tgen.net["r1"] + .cmd( + 'vtysh -c "show running ospfd" | grep "^ no ip ospf capability opaque"' + ) + .rstrip() + ) + assertmsg = ( + "'no ip ospf capability opaque' applied, but not present in configuration" + ) + assert no_capability_opaque_cfg == " no ip ospf capability opaque", assertmsg + + # STEP 3 in test_ospf_opaque_interface_disable and STEP 58 in CI tests + step("Verify the ospf opaque option is not applied to the r1 interface") + r1_interface_without_opaque = { + "interfaces": { + "r1-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.1", + "ospfIfType": "Broadcast", + "opaqueCapable": False, + } + } + } + r1_interface_with_opaque = { + "interfaces": { + "r1-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.1", + "ospfIfType": "Broadcast", + "opaqueCapable": True, + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + r1_neighbor_without_opaque = { + "neighbors": { + "2.0.0.0": [ + { + "optionsList": "*|-|-|-|-|-|E|-", + } + ] + } + } + r2_neighbor_without_opaque = { + "neighbors": { + "1.0.0.0": [ + { + "optionsList": "*|-|-|-|-|-|E|-", + } + ] + } + } + # STEP 4 in test_ospf_opaque_interface_disable and STEP 59 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 5 in test_ospf_opaque_interface_disable and STEP 60 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 6 in test_ospf_opaque_interface_disable and STEP 61 in CI tests + step( + "Verify no r2 configuration of 'no ip ospf capability opaque' in r2 configuration" + ) + rc, _, _ = tgen.net["r2"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r2 configuration" + assert rc, assertmsg + + # STEP 7 in test_ospf_opaque_interface_disable and STEP 62 in CI tests + step("Verify the ospf opaque option is applied to the r2 interface") + r2_interface_without_opaque = { + "interfaces": { + "r2-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.2", + "ospfIfType": "Broadcast", + "opaqueCapable": False, + } + } + } + r2_interface_with_opaque = { + "interfaces": { + "r2-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.2", + "ospfIfType": "Broadcast", + "opaqueCapable": True, + } + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF interface has opaque capability disabled" + assert result is None, assertmsg + + # STEP 8 in test_ospf_opaque_interface_disable and STEP 63 in CI tests + step("Install opaque LSAs on r1") + pread = r2.popen( + ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"], + encoding=None, # don't buffer + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + p = r1.popen( + [ + apibin, + "-v", + "add,9,10.0.1.1,230,1,feedaceedeadbeef", + "add,10,1.2.3.4,231,1,feedaceecafebeef", + "add,11,232,1,feedaceebaddbeef", + "wait,20", + ] + ) + opaque_LSAs_in_database = { + "areas": { + "1.2.3.4": { + "linkLocalOpaqueLsa": [ + { + "lsId": "230.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "linkLocalOpaqueLsaCount": 1, + "areaLocalOpaqueLsa": [ + { + "lsId": "231.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "areaLocalOpaqueLsaCount": 1, + }, + }, + "asExternalOpaqueLsa": [ + { + "lsId": "232.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "asExternalOpaqueLsaCount": 1, + } + opaque_area_empty_database = { + "routerId":"2.0.0.0", + "areaLocalOpaqueLsa":{ + "areas":{ + "1.2.3.4":[ + ] + } + } + } + + # STEP 9 in test_ospf_opaque_interface_disable and STEP 64 in CI tests + step("Check that LSAs are added on r1") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + # STEP 10 in test_ospf_opaque_interface_disable and STEP 65 in CI tests + step("Check that LSAs are not added on r2") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", + opaque_area_empty_database, True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF area database contains opaque LSAs" + assert result is None, assertmsg + + # STEP 11 in test_ospf_opaque_interface_disable and STEP 66 in CI tests + step("Enable OSPF opaque LSA Copability on r1's interface to r2") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nip ospf capability opaque") + time.sleep(15) + + # STEP 12 in test_ospf_opaque_interface_disable and STEP 67 in CI tests + step("Verify no r1 configuration of 'no ip ospf capability opaque'") + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r1 configuration" + assert rc, assertmsg + + # STEP 13 in test_ospf_opaque_interface_disable and STEP 68 in CI tests + step("Verify the ospf opaque option is applied to the r1 interface") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + r1_neighbor_with_opaque = { + "neighbors": { + "2.0.0.0": [ + { + "optionsList": "*|O|-|-|-|-|E|-", + } + ] + } + } + r2_neighbor_with_opaque = { + "neighbors": { + "1.0.0.0": [ + { + "optionsList": "*|O|-|-|-|-|E|-", + } + ] + } + } + # STEP 14 in test_ospf_opaque_interface_disable and STEP 69 in CI tests + step("Verify that the r1 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 15 in test_ospf_opaque_interface_disable and STEP 70 in CI tests + step("Verify that the r2 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 16 in test_ospf_opaque_interface_disable and STEP 71 in CI tests + step("Check that LSAs are now added to r2") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF database doesn't contains opaque LSAs" + assert result is None, assertmsg + + # STEP 17 in test_ospf_opaque_interface_disable and STEP 72 in CI tests + step( + "Disable Opaque Capability on r2's interface to r1 using the interface address" + ) + r2.vtysh_multicmd( + "conf t\ninterface r2-eth0\nno ip ospf capability opaque 10.0.1.2" + ) + + # STEP 18 in test_ospf_opaque_interface_disable and STEP 73 in CI tests + step("Clear the OSPF process on r2 to clear the OSPF LSDB") + r2.vtysh_multicmd("clear ip ospf process") + time.sleep(15) + + # STEP 19 in test_ospf_opaque_interface_disable and STEP 74 in CI tests + step("Verify the r2 configuration of 'no ip ospf capability opaque 10.0.1.2'") + no_capability_opaque_cfg = ( + tgen.net["r2"] + .cmd_nostatus( + 'vtysh -c "show running ospfd" | grep "^ no ip ospf capability opaque 10.0.1.2"' + ) + .rstrip() + ) + assertmsg = "'no ip ospf capability opaque 10.0.1.2' applied, but not present in configuration" + assert ( + no_capability_opaque_cfg == " no ip ospf capability opaque 10.0.1.2" + ), assertmsg + + # STEP 20 in test_ospf_opaque_interface_disable and STEP 75 in CI tests + step("Verify the ospf opaque option is not applied to the r2 interface") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + # STEP 21 in test_ospf_opaque_interface_disable and STEP 76 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 22 in test_ospf_opaque_interface_disable and STEP 77 in CI tests + step("Verify that the r2 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 23 in test_ospf_opaque_interface_disable and STEP 78 in CI tests + step("Verify that r1 still has the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + # STEP 24 in test_ospf_opaque_interface_disable and STEP 79 in CI tests + step("Verify that r2 doesn't have the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", + opaque_area_empty_database, True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF area database contains opaque LSAs" + assert result is None, assertmsg + + # STEP 25 in test_ospf_opaque_interface_disable and STEP 80 in CI tests + step("Remove the 'no ip ospf capability opaque 10.0.1.2' config from r2 ") + r2.vtysh_multicmd( + "conf t\ninterface r2-eth0\nip ospf capability opaque 10.0.1.2" + ) + time.sleep(15) + + # STEP 26 in test_ospf_opaque_interface_disable and STEP 81 in CI tests + step("Verify the r2 removal of 'no ip ospf capability opaque 10.0.1.2'") + rc, _, _ = tgen.net["r2"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r2 configuration" + assert rc, assertmsg + + # STEP 27 in test_ospf_opaque_interface_disable and STEP 82 in CI tests + step("Verify the ospf opaque option is applied to the r2 interface") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + # STEP 28 in test_ospf_opaque_interface_disable and STEP 83 in CI tests + step("Verify that the r2 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 29 in test_ospf_opaque_interface_disable and STEP 84 in CI tests + step("Verify that the r1 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 30 in test_ospf_opaque_interface_disable and STEP 85 in CLI tests + step("Verify that r2 now has the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + except Exception: + if p: + p.terminate() + if p.wait(): + comm_error(p) + p = None + raise + finally: + if pread: + pread.terminate() + pread.wait() + if p: + p.terminate() + p.wait() + + +@pytest.mark.parametrize("tgen", [2], indirect=True) +def test_ospf_opaque_interface_disable(tgen): + apibin = os.path.join(CLIENTDIR, "ospfclient.py") + rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) + _test_opaque_interface_disable(tgen, apibin) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index c45ac82d30..05036fa7ad 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -255,7 +255,7 @@ def test_route_map_usage(): ) ok, result = topotest.run_and_expect( - check_static_map_correct_runs, "", count=5, wait=1 + check_static_map_correct_runs, "", count=10, wait=1 ) assert ok, result @@ -275,7 +275,7 @@ def test_route_map_usage(): ) ok, result = topotest.run_and_expect( - check_sharp_map_correct_runs, "", count=5, wait=1 + check_sharp_map_correct_runs, "", count=10, wait=1 ) assert ok, result diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 69a986ba0d..3a7561cb69 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -1577,11 +1577,31 @@ def compare_context_objects(newconf, running): pcclist_to_del = [] candidates_to_add = [] delete_bgpd = False + area_stub_no_sum = "area (\S+) stub no-summary" # Find contexts that are in newconf but not in running # Find contexts that are in running but not in newconf for (running_ctx_keys, running_ctx) in iteritems(running.contexts): + if running_ctx_keys in newconf.contexts: + newconf_ctx = newconf.contexts[running_ctx_keys] + + for line in running_ctx.lines: + # ospf area <> stub no-summary line removal requires + # to remoe area <> stub as no form of original + # retains the stub form. + # lines_to_del will contain: + # no area <x> stub no-summary and + # no area <x> stub + if ( + running_ctx_keys[0].startswith("router ospf") + and line not in newconf_ctx.dlines + ): + re_area_stub_no_sum = re.search(area_stub_no_sum, line) + if re_area_stub_no_sum: + new_del_line = "area %s stub" % re_area_stub_no_sum.group(1) + lines_to_del.append((running_ctx_keys, new_del_line)) + if running_ctx_keys not in newconf.contexts: # We check that the len is 1 here so that we only look at ('router bgp 10') diff --git a/zebra/interface.c b/zebra/interface.c index e923c0a187..989763d13c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -610,6 +610,11 @@ void if_add_update(struct interface *ifp) if_addr_wakeup(ifp); + if (if_data->mpls_config == IF_ZEBRA_DATA_ON) + dplane_intf_mpls_modify_state(ifp, true); + else if (if_data->mpls_config == IF_ZEBRA_DATA_OFF) + dplane_intf_mpls_modify_state(ifp, false); + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "interface %s vrf %s(%u) index %d becomes active.", @@ -1368,6 +1373,13 @@ static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx, bool pd_reason_val; bool down; + if (!ifp) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Can't find ifp", __func__); + + return; + } + dp_res = dplane_ctx_get_status(ctx); pd_reason_val = dplane_ctx_get_intf_pd_reason_val(ctx); down = dplane_ctx_intf_is_protodown(ctx); @@ -1444,7 +1456,7 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, linkdown_set = &zrouter.default_linkdownv6; } } else { - zif = ifp ? ifp->info : NULL; + zif = ifp->info; if (!zif) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -1524,10 +1536,16 @@ static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, if (exist_id != VRF_DEFAULT) { vrf = vrf_lookup_by_id(exist_id); - flog_err( - EC_ZEBRA_VRF_MISCONFIGURED, - "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", - name, ifindex, vrf->name, vrf->vrf_id); + if (vrf) + flog_err(EC_ZEBRA_VRF_MISCONFIGURED, + "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", + name, ifindex, vrf->name, + vrf->vrf_id); + else + flog_err(EC_ZEBRA_VRF_NOT_FOUND, + "VRF %s id %u does not exist", + name, ifindex); + exit(-1); } } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index f0d4427688..c98f1ce60c 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1289,18 +1289,15 @@ int netlink_request(struct nlsock *nl, void *req) return 0; } -static int nl_batch_read_resp(struct nl_batch *bth) +static int nl_batch_read_resp(struct nl_batch *bth, struct nlsock *nl) { struct nlmsghdr *h; struct sockaddr_nl snl; struct msghdr msg = {}; int status, seq; - struct nlsock *nl; struct zebra_dplane_ctx *ctx; bool ignore_msg; - nl = kernel_netlink_nlsock_lookup(bth->zns->sock); - msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); @@ -1493,7 +1490,7 @@ static void nl_batch_send(struct nl_batch *bth) err = true; if (!err) { - if (nl_batch_read_resp(bth) == -1) + if (nl_batch_read_resp(bth, nl) == -1) err = true; } } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 47ecbc0b44..11b7b7cf82 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -256,12 +256,11 @@ void redistribute_delete(const struct route_node *rn, table = new_re->table; } - zlog_debug( - "%u:%u%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", - vrfid, table, rn, old_re, old_inst, - old_re ? zebra_route_string(old_re->type) : "None", - new_re, new_inst, - new_re ? zebra_route_string(new_re->type) : "None"); + zlog_debug("(%u:%u):%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", + vrfid, table, rn, old_re, old_inst, + old_re ? zebra_route_string(old_re->type) : "None", + new_re, new_inst, + new_re ? zebra_route_string(new_re->type) : "None"); } /* Skip invalid (e.g. linklocal) prefix */ diff --git a/zebra/rib.h b/zebra/rib.h index 65cc1ffab9..64bbaf3e76 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -167,6 +167,10 @@ struct route_entry { #define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type) +/* Define route types that are equivalent to "connected". */ +#define RIB_CONNECTED_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_CONNECT || (R)->type == ZEBRA_ROUTE_NHRP) + /* meta-queue structure: * sub-queue 0: nexthop group objects * sub-queue 1: EVPN/VxLAN objects diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e44f6ee4e0..bb507893b0 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2392,7 +2392,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, continue; } - if ((match->type == ZEBRA_ROUTE_CONNECT) || + /* If the candidate match's type is considered "connected", + * we consider it first. + */ + if (RIB_CONNECTED_ROUTE(match) || (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) { match = zebra_nhg_connected_ifindex(rn, match, nexthop->ifindex); @@ -2413,6 +2416,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, return 0; } + /* NHRP special case: need to indicate onlink */ + if (match->type == ZEBRA_ROUTE_NHRP) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "%s: CONNECT match %p (%pNG), newhop %pNHv", |
