Version in base suite: 8.4.2-1 Base version: frr_8.4.2-1 Target version: frr_8.4.4-1.1~deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/frr/frr_8.4.2-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/frr/frr_8.4.4-1.1~deb12u1.dsc babeld/babel_filter.c | 7 bfdd/bfd_packet.c | 2 bfdd/bfdd_nb.c | 2 bfdd/bfdd_nb.h | 3 bfdd/bfdd_nb_config.c | 38 bgpd/bgp_attr.c | 108 +- bgpd/bgp_bmp.c | 8 bgpd/bgp_dump.c | 3 bgpd/bgp_ecommunity.c | 29 bgpd/bgp_evpn.c | 17 bgpd/bgp_evpn.h | 2 bgpd/bgp_evpn_mh.c | 6 bgpd/bgp_evpn_vty.c | 33 bgpd/bgp_flowspec.c | 16 bgpd/bgp_flowspec.h | 2 bgpd/bgp_keepalives.c | 16 bgpd/bgp_lcommunity.c | 18 bgpd/bgp_mplsvpn.c | 4 bgpd/bgp_network.c | 9 bgpd/bgp_open.c | 14 bgpd/bgp_packet.c | 2 bgpd/bgp_packet.h | 26 bgpd/bgp_route.c | 183 ++-- bgpd/bgp_route.h | 1 bgpd/bgp_updgrp_adv.c | 27 bgpd/bgp_vty.c | 56 - bgpd/bgpd.c | 63 - bgpd/rfapi/rfapi_import.c | 15 configure.ac | 2 debian/changelog | 24 debian/control | 1 debian/gbp.conf | 7 debian/patches/CVE-2023-38802.patch | 131 +++ debian/patches/CVE-2023-41358.patch | 100 ++ debian/patches/CVE-2023-41360.patch | 30 debian/patches/CVE-2023-41361.patch | 43 + debian/patches/series | 3 debian/watch | 4 lib/bfd.c | 6 lib/command.c | 8 lib/filter_cli.c | 2 lib/filter_nb.c | 2 lib/if_rmap.c | 2 lib/link_state.c | 14 lib/vty.c | 17 lib/vty.h | 4 lib/yang_translator.c | 14 ospf6d/ospf6_flood.c | 6 ospf6d/ospf6_gr_helper.c | 5 ospf6d/ospf6_lsa.c | 4 ospf6d/ospf6_message.c | 49 - ospf6d/ospf6_neighbor.c | 21 ospfclient/ospf_apiclient.c | 4 ospfclient/ospfclient.py | 193 ++-- ospfclient/subdir.am | 1 ospfd/ospf_apiserver.c | 77 + ospfd/ospf_apiserver.h | 4 ospfd/ospf_interface.c | 22 ospfd/ospf_lsa.c | 41 - ospfd/ospf_nsm.c | 13 ospfd/ospf_opaque.c | 39 ospfd/ospf_packet.c | 91 +- ospfd/ospf_route.c | 65 - ospfd/ospf_snmp.c | 6 ospfd/ospf_spf.c | 3 ospfd/ospf_ti_lfa.c | 24 ospfd/ospf_vty.c | 9 ospfd/subdir.am | 8 pbrd/pbr_vty.c | 12 pceplib/pcep_utils_counters.h | 1 pimd/pim_bsm.c | 5 pimd/pim_mroute.c | 61 + pimd/pim_neighbor.c | 6 pimd/pim_oil.c | 25 pimd/pim_oil.h | 1 pimd/pim_util.c | 2 pimd/pim_zebra.c | 12 redhat/frr.spec.in | 8 tests/bgpd/test_mp_attr.c | 4 tests/topotests/bgp_confederation_astype/r1/bgpd.conf | 12 tests/topotests/bgp_confederation_astype/r1/zebra.conf | 7 tests/topotests/bgp_confederation_astype/r2/bgpd.conf | 13 tests/topotests/bgp_confederation_astype/r2/zebra.conf | 4 tests/topotests/bgp_confederation_astype/r3/bgpd.conf | 10 tests/topotests/bgp_confederation_astype/r3/zebra.conf | 4 tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py | 140 +++ tests/topotests/bgp_prefix_list_any/r1/bgpd.conf | 15 tests/topotests/bgp_prefix_list_any/r1/zebra.conf | 5 tests/topotests/bgp_prefix_list_any/r2/bgpd.conf | 50 + tests/topotests/bgp_prefix_list_any/r2/zebra.conf | 5 tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py | 105 ++ tests/topotests/bgp_route_map_delay_timer/r1/bgpd.conf | 24 tests/topotests/bgp_route_map_delay_timer/r1/zebra.conf | 4 tests/topotests/bgp_route_map_delay_timer/r2/bgpd.conf | 4 tests/topotests/bgp_route_map_delay_timer/r2/zebra.conf | 4 tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py | 120 ++ tests/topotests/bgp_route_origin_parser/pe1/bgpd.conf | 2 tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py | 129 +++ tests/topotests/ospfapi/r1/ospfd.conf | 7 tests/topotests/ospfapi/r1/zebra.conf | 2 tests/topotests/ospfapi/r2/ospfd.conf | 2 tests/topotests/ospfapi/r3/ospfd.conf | 2 tests/topotests/ospfapi/r4/ospfd.conf | 7 tests/topotests/ospfapi/r4/zebra.conf | 2 tests/topotests/ospfapi/test_ospf_clientapi.py | 407 +++++++--- tools/etc/rsyslog.d/45-frr.conf | 2 tools/frr-reload.py | 19 vrrpd/vrrp.c | 3 vtysh/vtysh.h | 2 vtysh/vtysh_user.c | 15 zebra/if_netlink.c | 18 zebra/main.c | 2 zebra/rib.h | 8 zebra/zapi_msg.c | 16 zebra/zebra_dplane.c | 9 zebra/zebra_evpn_mac.c | 21 zebra/zebra_netns_notify.c | 11 zebra/zebra_rib.c | 66 + 118 files changed, 2485 insertions(+), 739 deletions(-) diff -Nru frr-8.4.2/babeld/babel_filter.c frr-8.4.4/babeld/babel_filter.c --- frr-8.4.2/babeld/babel_filter.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/babeld/babel_filter.c 2023-06-16 04:41:18.000000000 +0000 @@ -44,15 +44,18 @@ struct prefix_list *plist; int distribute; struct babel *babel; + afi_t family; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) { uchar_to_inaddr(&p.u.prefix4, prefix); distribute = output ? DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN; + family = AFI_IP; } else { uchar_to_in6addr(&p.u.prefix6, prefix); distribute = output ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN; + family = AFI_IP6; } if (babel_ifp != NULL && babel_ifp->list[distribute]) { @@ -79,7 +82,7 @@ dist = distribute_lookup (babel->distribute_ctx, NULL); if (dist) { if (dist->list[distribute]) { - alist = access_list_lookup (p.family, dist->list[distribute]); + alist = access_list_lookup (family, dist->list[distribute]); if (alist) { if (access_list_apply (alist, &p) == FILTER_DENY) { @@ -90,7 +93,7 @@ } } if (dist->prefix[distribute]) { - plist = prefix_list_lookup (p.family, dist->prefix[distribute]); + plist = prefix_list_lookup (family, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER,"%pFX filtered by distribute %s", diff -Nru frr-8.4.2/bfdd/bfd_packet.c frr-8.4.4/bfdd/bfd_packet.c --- frr-8.4.2/bfdd/bfd_packet.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bfdd/bfd_packet.c 2023-06-16 04:41:18.000000000 +0000 @@ -896,7 +896,7 @@ /* * We may have a situation where received packet is on wrong vrf */ - if (bfd && bfd->vrf && bfd->vrf != bvrf->vrf) { + if (bfd && bfd->vrf && bfd->vrf->vrf_id != vrfid) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "wrong vrfid."); return; diff -Nru frr-8.4.2/bfdd/bfdd_nb.c frr-8.4.4/bfdd/bfdd_nb.c --- frr-8.4.2/bfdd/bfdd_nb.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bfdd/bfdd_nb.c 2023-06-16 04:41:18.000000000 +0000 @@ -88,7 +88,6 @@ .xpath = "/frr-bfdd:bfdd/bfd/profile/minimum-ttl", .cbs = { .modify = bfdd_bfd_profile_minimum_ttl_modify, - .destroy = bfdd_bfd_profile_minimum_ttl_destroy, .cli_show = bfd_cli_show_minimum_ttl, } }, @@ -375,7 +374,6 @@ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl", .cbs = { .modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify, - .destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy, .cli_show = bfd_cli_show_minimum_ttl, } }, diff -Nru frr-8.4.2/bfdd/bfdd_nb.h frr-8.4.4/bfdd/bfdd_nb.h --- frr-8.4.2/bfdd/bfdd_nb.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bfdd/bfdd_nb.h 2023-06-16 04:41:18.000000000 +0000 @@ -39,7 +39,6 @@ int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args); -int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args); int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args); @@ -142,8 +141,6 @@ struct nb_cb_modify_args *args); int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify( struct nb_cb_modify_args *args); -int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy( - struct nb_cb_destroy_args *args); struct yang_data * bfdd_bfd_sessions_multi_hop_stats_local_discriminator_get_elem( struct nb_cb_get_elem_args *args); diff -Nru frr-8.4.2/bfdd/bfdd_nb_config.c frr-8.4.4/bfdd/bfdd_nb_config.c --- frr-8.4.2/bfdd/bfdd_nb_config.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bfdd/bfdd_nb_config.c 2023-06-16 04:41:18.000000000 +0000 @@ -437,20 +437,6 @@ return NB_OK; } -int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args) -{ - struct bfd_profile *bp; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - bp = nb_running_get_entry(args->dnode, NULL, true); - bp->minimum_ttl = BFD_DEF_MHOP_TTL; - bfd_profile_update(bp); - - return NB_OK; -} - /* * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode */ @@ -872,28 +858,4 @@ bfd_session_apply(bs); return NB_OK; -} - -int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy( - struct nb_cb_destroy_args *args) -{ - struct bfd_session *bs; - - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - return NB_OK; - - case NB_EV_APPLY: - break; - - case NB_EV_ABORT: - return NB_OK; - } - - bs = nb_running_get_entry(args->dnode, NULL, true); - bs->peer_profile.minimum_ttl = BFD_DEF_MHOP_TTL; - bfd_session_apply(bs); - - return NB_OK; } diff -Nru frr-8.4.2/bgpd/bgp_attr.c frr-8.4.4/bgpd/bgp_attr.c --- frr-8.4.2/bgpd/bgp_attr.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_attr.c 2023-06-16 04:41:18.000000000 +0000 @@ -1546,6 +1546,14 @@ */ struct aspath *aspath; + /* Refresh peer's type. If we set e.g.: AS_EXTERNAL/AS_INTERNAL, + * then peer->sort remains BGP_PEER_EBGP/IBGP, hence we need to + * have an actual type before checking. + * This is especially a case for BGP confederation peers, to avoid + * receiving and treating AS_PATH as malformed. + */ + (void)peer_sort(peer); + /* Confederation sanity check. */ if ((peer->sort == BGP_PEER_CONFED && !aspath_left_confed_check(attr->aspath)) @@ -2748,9 +2756,21 @@ uint8_t sid_type, sid_flags; char buf[BUFSIZ]; + /* + * Check that we actually have at least as much data as + * specified by the length field + */ + if (STREAM_READABLE(peer->curr) < length) { + flog_err( + EC_BGP_ATTR_LEN, + "Prefix SID specifies length %hu, but only %zu bytes remain", + length, STREAM_READABLE(peer->curr)); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + if (type == BGP_PREFIX_SID_LABEL_INDEX) { - if (STREAM_READABLE(peer->curr) < length - || length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) { + if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) { flog_err(EC_BGP_ATTR_LEN, "Prefix SID label index length is %hu instead of %u", length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH); @@ -2772,12 +2792,8 @@ /* Store label index; subsequently, we'll check on * address-family */ attr->label_index = label_index; - } - - /* Placeholder code for the IPv6 SID type */ - else if (type == BGP_PREFIX_SID_IPV6) { - if (STREAM_READABLE(peer->curr) < length - || length != BGP_PREFIX_SID_IPV6_LENGTH) { + } else if (type == BGP_PREFIX_SID_IPV6) { + if (length != BGP_PREFIX_SID_IPV6_LENGTH) { flog_err(EC_BGP_ATTR_LEN, "Prefix SID IPv6 length is %hu instead of %u", length, BGP_PREFIX_SID_IPV6_LENGTH); @@ -2791,10 +2807,7 @@ stream_getw(peer->curr); stream_get(&ipv6_sid, peer->curr, 16); - } - - /* Placeholder code for the Originator SRGB type */ - else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) { + } else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) { /* * ietf-idr-bgp-prefix-sid-05: * Length is the total length of the value portion of the @@ -2820,19 +2833,6 @@ } /* - * Check that we actually have at least as much data as - * specified by the length field - */ - if (STREAM_READABLE(peer->curr) < length) { - flog_err(EC_BGP_ATTR_LEN, - "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain", - length, STREAM_READABLE(peer->curr)); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - args->total); - } - - /* * Check that the portion of the TLV containing the sequence of * SRGBs corresponds to a multiple of the SRGB size; to get * that length, we skip the 16 bit flags field @@ -2855,12 +2855,8 @@ stream_get(&srgb_base, peer->curr, 3); stream_get(&srgb_range, peer->curr, 3); } - } - - /* Placeholder code for the VPN-SID Service type */ - else if (type == BGP_PREFIX_SID_VPN_SID) { - if (STREAM_READABLE(peer->curr) < length - || length != BGP_PREFIX_SID_VPN_SID_LENGTH) { + } else if (type == BGP_PREFIX_SID_VPN_SID) { + if (length != BGP_PREFIX_SID_VPN_SID_LENGTH) { flog_err(EC_BGP_ATTR_LEN, "Prefix SID VPN SID length is %hu instead of %u", length, BGP_PREFIX_SID_VPN_SID_LENGTH); @@ -2896,39 +2892,22 @@ attr->srv6_vpn->sid_flags = sid_flags; sid_copy(&attr->srv6_vpn->sid, &ipv6_sid); attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn); - } - - /* Placeholder code for the SRv6 L3 Service type */ - else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) { - if (STREAM_READABLE(peer->curr) < length) { + } else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) { + if (STREAM_READABLE(peer->curr) < 1) { flog_err( EC_BGP_ATTR_LEN, - "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain", - length, STREAM_READABLE(peer->curr)); - return bgp_attr_malformed(args, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - args->total); + "Prefix SID SRV6 L3 Service not enough data left, it must be at least 1 byte"); + return bgp_attr_malformed( + args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); } - /* ignore reserved */ stream_getc(peer->curr); return bgp_attr_srv6_service(args); } - /* Placeholder code for Unsupported TLV */ else { - - if (STREAM_READABLE(peer->curr) < length) { - flog_err( - EC_BGP_ATTR_LEN, - "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE", - length, STREAM_READABLE(peer->curr)); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - args->total); - } - if (bgp_debug_update(peer, NULL, NULL, 1)) zlog_debug( "%s attr Prefix-SID sub-type=%u is not supported, skipped", @@ -4002,8 +3981,21 @@ aspath = aspath_delete_confed_seq(aspath); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { - /* Stuff our path CONFED_ID on the front */ - aspath = aspath_add_seq(aspath, bgp->confed_id); + /* A confed member, so we need to do the + * AS_CONFED_SEQUENCE thing if it's outside a common + * administration. + * Configured confederation peers MUST be validated + * under BGP_PEER_CONFED, but if we have configured + * remote-as as AS_EXTERNAL, we need to check again + * if the peer belongs to us. + */ + if (bgp_confederation_peers_check(bgp, peer->as)) { + aspath = aspath_add_confed_seq(aspath, + peer->local_as); + } else { + /* Stuff our path CONFED_ID on the front */ + aspath = aspath_add_seq(aspath, bgp->confed_id); + } } else { if (peer->change_local_as) { /* If replace-as is specified, we only use the @@ -4396,6 +4388,10 @@ * there! (JK) * Folks, talk to me: what is reasonable here!? */ + + /* Make sure dup aspath before the modification */ + if (aspath == attr->aspath) + aspath = aspath_dup(attr->aspath); aspath = aspath_delete_confed_seq(aspath); stream_putc(s, diff -Nru frr-8.4.2/bgpd/bgp_bmp.c frr-8.4.4/bgpd/bgp_bmp.c --- frr-8.4.2/bgpd/bgp_bmp.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_bmp.c 2023-06-16 04:41:18.000000000 +0000 @@ -402,13 +402,13 @@ /* Local Port, Remote Port */ if (peer->su_local->sa.sa_family == AF_INET6) - stream_putw(s, peer->su_local->sin6.sin6_port); + stream_putw(s, htons(peer->su_local->sin6.sin6_port)); else if (peer->su_local->sa.sa_family == AF_INET) - stream_putw(s, peer->su_local->sin.sin_port); + stream_putw(s, htons(peer->su_local->sin.sin_port)); if (peer->su_remote->sa.sa_family == AF_INET6) - stream_putw(s, peer->su_remote->sin6.sin6_port); + stream_putw(s, htons(peer->su_remote->sin6.sin6_port)); else if (peer->su_remote->sa.sa_family == AF_INET) - stream_putw(s, peer->su_remote->sin.sin_port); + stream_putw(s, htons(peer->su_remote->sin.sin_port)); static const uint8_t dummy_open[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff -Nru frr-8.4.2/bgpd/bgp_dump.c frr-8.4.4/bgpd/bgp_dump.c --- frr-8.4.2/bgpd/bgp_dump.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_dump.c 2023-06-16 04:41:18.000000000 +0000 @@ -856,8 +856,7 @@ memset(&bgp_dump_routes, 0, sizeof(bgp_dump_routes)); bgp_dump_obuf = - stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE * 2) - + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE); + stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW); install_node(&bgp_dump_node); diff -Nru frr-8.4.2/bgpd/bgp_ecommunity.c frr-8.4.4/bgpd/bgp_ecommunity.c --- frr-8.4.2/bgpd/bgp_ecommunity.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_ecommunity.c 2023-06-16 04:41:18.000000000 +0000 @@ -520,6 +520,8 @@ uint8_t ecomm_type; char buf[INET_ADDRSTRLEN + 1]; struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr; + uint64_t tmp_as = 0; + /* Skip white space. */ while (isspace((unsigned char)*p)) { p++; @@ -598,9 +600,18 @@ goto error; endptr++; - as = strtoul(endptr, &endptr, 10); - if (*endptr != '\0' || as == BGP_AS4_MAX) + errno = 0; + tmp_as = strtoul(endptr, &endptr, 10); + /* 'unsigned long' is a uint64 on 64-bit + * systems, and uint32 on 32-bit systems. So for + * 64-bit we can just directly check the value + * against BGP_AS4_MAX/UINT32_MAX, and for + * 32-bit we can check for errno (set to ERANGE + * upon overflow). + */ + if (*endptr != '\0' || tmp_as == BGP_AS4_MAX || errno) goto error; + as = (as_t)tmp_as; memcpy(buf, p, (limit - p)); buf[limit - p] = '\0'; @@ -642,9 +653,19 @@ goto error; } else { /* ASN */ - as = strtoul(buf, &endptr, 10); - if (*endptr != '\0' || as == BGP_AS4_MAX) + errno = 0; + tmp_as = strtoul(buf, &endptr, 10); + /* 'unsigned long' is a uint64 on 64-bit + * systems, and uint32 on 32-bit systems. So for + * 64-bit we can just directly check the value + * against BGP_AS4_MAX/UINT32_MAX, and for + * 32-bit we can check for errno (set to ERANGE + * upon overflow). + */ + if (*endptr != '\0' || tmp_as > BGP_AS4_MAX || + errno) goto error; + as = (as_t)tmp_as; } } else if (*p == '.') { if (separator) diff -Nru frr-8.4.2/bgpd/bgp_evpn.c frr-8.4.4/bgpd/bgp_evpn.c --- frr-8.4.2/bgpd/bgp_evpn.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_evpn.c 2023-06-16 04:41:18.000000000 +0000 @@ -4982,7 +4982,7 @@ } int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw) + struct bgp_nlri *packet, bool withdraw) { uint8_t *pnt; uint8_t *lim; @@ -5564,6 +5564,14 @@ l3vni); return -1; } + + if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { + flog_err(EC_BGP_NO_DFLT, + "Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down", + l3vni); + return -1; + } + as = bgp_evpn->as; /* if the BGP vrf instance doesn't exist - create one */ @@ -5703,6 +5711,13 @@ return -1; } + if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { + flog_err(EC_BGP_NO_DFLT, + "Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down", + l3vni); + return -1; + } + /* Remove remote routes from BGT VRF even if BGP_VRF_AUTO is configured, * bgp_delete would not remove/decrement bgp_path_info of the ip_prefix * routes. This will uninstalling the routes from zebra and decremnt the diff -Nru frr-8.4.2/bgpd/bgp_evpn.h frr-8.4.4/bgpd/bgp_evpn.h --- frr-8.4.2/bgpd/bgp_evpn.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_evpn.h 2023-06-16 04:41:18.000000000 +0000 @@ -186,7 +186,7 @@ struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw); + struct bgp_nlri *packet, bool withdraw); extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, const struct prefix *p, struct bgp_path_info *ri); diff -Nru frr-8.4.2/bgpd/bgp_evpn_mh.c frr-8.4.4/bgpd/bgp_evpn_mh.c --- frr-8.4.2/bgpd/bgp_evpn_mh.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_evpn_mh.c 2023-06-16 04:41:18.000000000 +0000 @@ -2576,7 +2576,8 @@ bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str)); vty_out(vty, "%-30s %-5s %-21pRD %-8d %s\n", es->esi_str, - type_str, &es->es_base_frag->prd, + type_str, + es->es_base_frag ? &es->es_base_frag->prd : NULL, listcount(es->es_evi_list), vtep_str); } } @@ -2652,7 +2653,8 @@ vty_out(vty, "ESI: %s\n", es->esi_str); vty_out(vty, " Type: %s\n", type_str); - vty_out(vty, " RD: %pRD\n", &es->es_base_frag->prd); + vty_out(vty, " RD: %pRD\n", + es->es_base_frag ? &es->es_base_frag->prd : NULL); vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip); if (es->flags & BGP_EVPNES_LOCAL) vty_out(vty, " Local ES DF preference: %u\n", diff -Nru frr-8.4.2/bgpd/bgp_evpn_vty.c frr-8.4.4/bgpd/bgp_evpn_vty.c --- frr-8.4.2/bgpd/bgp_evpn_vty.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_evpn_vty.c 2023-06-16 04:41:18.000000000 +0000 @@ -4629,8 +4629,14 @@ evpn_show_all_routes(vty, bgp, type, json, detail); + /* + * This is an extremely expensive operation at scale + * and as such we need to save as much time as is + * possible. + */ if (uj) - vty_json(vty, json); + vty_json_no_pretty(vty, json); + return CMD_SUCCESS; } @@ -6054,15 +6060,17 @@ return CMD_WARNING; } - ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0); - if (!ecomadd) { - vty_out(vty, "%% Malformed Route Target list\n"); - return CMD_WARNING; - } - ecommunity_str(ecomadd); - /* Add/update the import route-target */ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) { + /* Note that first of the two RTs is created for "both" type */ + ecomadd = ecommunity_str2com(argv[2]->arg, + ECOMMUNITY_ROUTE_TARGET, 0); + if (!ecomadd) { + vty_out(vty, "%% Malformed Route Target list\n"); + return CMD_WARNING; + } + ecommunity_str(ecomadd); + /* Do nothing if we already have this import route-target */ if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd)) evpn_configure_import_rt(bgp, vpn, ecomadd); @@ -6070,6 +6078,15 @@ /* Add/update the export route-target */ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) { + /* Note that second of the two RTs is created for "both" type */ + ecomadd = ecommunity_str2com(argv[2]->arg, + ECOMMUNITY_ROUTE_TARGET, 0); + if (!ecomadd) { + vty_out(vty, "%% Malformed Route Target list\n"); + return CMD_WARNING; + } + ecommunity_str(ecomadd); + /* Do nothing if we already have this export route-target */ if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd)) evpn_configure_export_rt(bgp, vpn, ecomadd); diff -Nru frr-8.4.2/bgpd/bgp_flowspec.c frr-8.4.4/bgpd/bgp_flowspec.c --- frr-8.4.2/bgpd/bgp_flowspec.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_flowspec.c 2023-06-16 04:41:18.000000000 +0000 @@ -95,7 +95,7 @@ } int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw) + struct bgp_nlri *packet, bool withdraw) { uint8_t *pnt; uint8_t *lim; @@ -112,6 +112,13 @@ afi = packet->afi; safi = packet->safi; + /* + * All other AFI/SAFI's treat no attribute as a implicit + * withdraw. Flowspec should as well. + */ + if (!attr) + withdraw = true; + if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED) { flog_err(EC_BGP_FLOWSPEC_PACKET, "BGP flowspec nlri length maximum reached (%u)", @@ -141,6 +148,13 @@ psize); return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } + + if (psize == 0) { + flog_err(EC_BGP_FLOWSPEC_PACKET, + "Flowspec NLRI length 0 which makes no sense"); + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; + } + if (bgp_fs_nlri_validate(pnt, psize, afi) < 0) { flog_err( EC_BGP_FLOWSPEC_PACKET, diff -Nru frr-8.4.2/bgpd/bgp_flowspec.h frr-8.4.4/bgpd/bgp_flowspec.h --- frr-8.4.2/bgpd/bgp_flowspec.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_flowspec.h 2023-06-16 04:41:18.000000000 +0000 @@ -28,7 +28,7 @@ #define BGP_FLOWSPEC_NLRI_STRING_MAX 512 extern int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw); + struct bgp_nlri *packet, bool withdraw); extern void bgp_flowspec_vty_init(void); diff -Nru frr-8.4.2/bgpd/bgp_keepalives.c frr-8.4.4/bgpd/bgp_keepalives.c --- frr-8.4.2/bgpd/bgp_keepalives.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_keepalives.c 2023-06-16 04:41:18.000000000 +0000 @@ -36,6 +36,10 @@ #include "bgpd/bgp_keepalives.h" /* clang-format on */ +DEFINE_MTYPE_STATIC(BGPD, BGP_PKAT, "Peer KeepAlive Timer"); +DEFINE_MTYPE_STATIC(BGPD, BGP_COND, "BGP Peer pthread Conditional"); +DEFINE_MTYPE_STATIC(BGPD, BGP_MUTEX, "BGP Peer pthread Mutex"); + /* * Peer KeepAlive Timer. * Associates a peer with the time of its last keepalive. @@ -54,7 +58,7 @@ static struct pkat *pkat_new(struct peer *peer) { - struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat)); + struct pkat *pkat = XMALLOC(MTYPE_BGP_PKAT, sizeof(struct pkat)); pkat->peer = peer; monotime(&pkat->last); return pkat; @@ -62,7 +66,7 @@ static void pkat_del(void *pkat) { - XFREE(MTYPE_TMP, pkat); + XFREE(MTYPE_BGP_PKAT, pkat); } @@ -158,8 +162,8 @@ pthread_mutex_destroy(peerhash_mtx); pthread_cond_destroy(peerhash_cond); - XFREE(MTYPE_TMP, peerhash_mtx); - XFREE(MTYPE_TMP, peerhash_cond); + XFREE(MTYPE_BGP_MUTEX, peerhash_mtx); + XFREE(MTYPE_BGP_COND, peerhash_cond); } /* @@ -184,8 +188,8 @@ */ rcu_read_unlock(); - peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); - peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); + peerhash_mtx = XCALLOC(MTYPE_BGP_MUTEX, sizeof(pthread_mutex_t)); + peerhash_cond = XCALLOC(MTYPE_BGP_COND, sizeof(pthread_cond_t)); /* initialize mutex */ pthread_mutex_init(peerhash_mtx, NULL); diff -Nru frr-8.4.2/bgpd/bgp_lcommunity.c frr-8.4.4/bgpd/bgp_lcommunity.c --- frr-8.4.2/bgpd/bgp_lcommunity.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_lcommunity.c 2023-06-16 04:41:18.000000000 +0000 @@ -211,12 +211,13 @@ } /* 1 space + lcom->size lcom strings + null terminator */ - size_t str_buf_sz = BUFSIZ; + size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2; str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz); + len = 0; for (i = 0; i < lcom->size; i++) { if (i > 0) - strlcat(str_buf, " ", str_buf_sz); + len = strlcat(str_buf, " ", str_buf_sz); pnt = lcom->val + (i * LCOMMUNITY_SIZE); pnt = ptr_get_be32(pnt, &global); @@ -229,11 +230,22 @@ snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1, local2); + /* + * Aliases can cause havoc, if the alias length is greater + * than the LCOMMUNITY_STRLEN for a particular item + * then we need to realloc the memory associated + * with the string so that it can fit + */ const char *com2alias = translate_alias ? bgp_community2alias(lcsb) : lcsb; + size_t individual_len = strlen(com2alias); + if (individual_len + len > str_buf_sz) { + str_buf_sz = individual_len + len + 1; + str_buf = XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, + str_buf_sz); + } len = strlcat(str_buf, com2alias, str_buf_sz); - assert((unsigned int)len < str_buf_sz); if (make_json) { json_string = json_object_new_string(com2alias); diff -Nru frr-8.4.2/bgpd/bgp_mplsvpn.c frr-8.4.4/bgpd/bgp_mplsvpn.c --- frr-8.4.2/bgpd/bgp_mplsvpn.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_mplsvpn.c 2023-06-16 04:41:18.000000000 +0000 @@ -815,7 +815,7 @@ struct bgp_path_info *new; struct bgp_path_info_extra *extra; uint32_t num_sids = 0; - void *parent = source_bpi; + struct bgp_path_info *parent = source_bpi; if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) num_sids = 1; @@ -1017,7 +1017,7 @@ new->extra->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( - (struct bgp_dest *)((struct bgp_path_info *)parent)->net); + (struct bgp_dest *)parent->net); if (bgp_orig) new->extra->bgp_orig = bgp_lock(bgp_orig); if (nexthop_orig) diff -Nru frr-8.4.2/bgpd/bgp_network.c frr-8.4.4/bgpd/bgp_network.c --- frr-8.4.2/bgpd/bgp_network.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_network.c 2023-06-16 04:41:18.000000000 +0000 @@ -790,9 +790,12 @@ if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer)) { - flog_err(EC_BGP_NH_UPD, - "%s: nexthop_set failed, resetting connection - intf %p", - peer->host, peer->nexthop.ifp); + flog_err( + EC_BGP_NH_UPD, + "%s: nexthop_set failed, resetting connection - intf %s", + peer->host, + peer->nexthop.ifp ? peer->nexthop.ifp->name + : "(Unknown)"); return -1; } return 0; diff -Nru frr-8.4.2/bgpd/bgp_open.c frr-8.4.4/bgpd/bgp_open.c --- frr-8.4.2/bgpd/bgp_open.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_open.c 2023-06-16 04:41:18.000000000 +0000 @@ -599,12 +599,24 @@ static int bgp_capability_llgr(struct peer *peer, struct capability_header *caphdr) { +/* + * +--------------------------------------------------+ + * | Address Family Identifier (16 bits) | + * +--------------------------------------------------+ + * | Subsequent Address Family Identifier (8 bits) | + * +--------------------------------------------------+ + * | Flags for Address Family (8 bits) | + * +--------------------------------------------------+ + * | Long-lived Stale Time (24 bits) | + * +--------------------------------------------------+ + */ +#define BGP_CAP_LLGR_MIN_PACKET_LEN 7 struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp(s) + caphdr->length; SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV); - while (stream_get_getp(s) + 4 <= end) { + while (stream_get_getp(s) + BGP_CAP_LLGR_MIN_PACKET_LEN <= end) { afi_t afi; safi_t safi; iana_afi_t pkt_afi = stream_getw(s); diff -Nru frr-8.4.2/bgpd/bgp_packet.c frr-8.4.4/bgpd/bgp_packet.c --- frr-8.4.2/bgpd/bgp_packet.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_packet.c 2023-06-16 04:41:18.000000000 +0000 @@ -346,7 +346,7 @@ * calling safi function and for evpn, passed as parameter */ int bgp_nlri_parse(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int mp_withdraw) + struct bgp_nlri *packet, bool mp_withdraw) { switch (packet->safi) { case SAFI_UNICAST: diff -Nru frr-8.4.2/bgpd/bgp_packet.h frr-8.4.4/bgpd/bgp_packet.h --- frr-8.4.2/bgpd/bgp_packet.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_packet.h 2023-06-16 04:41:18.000000000 +0000 @@ -57,26 +57,28 @@ } while (0) /* Packet send and receive function prototypes. */ -extern void bgp_keepalive_send(struct peer *); -extern void bgp_open_send(struct peer *); -extern void bgp_notify_send(struct peer *, uint8_t, uint8_t); -extern void bgp_notify_send_with_data(struct peer *, uint8_t, uint8_t, - uint8_t *, size_t); +extern void bgp_keepalive_send(struct peer *peer); +extern void bgp_open_send(struct peer *peer); +extern void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code); +extern void bgp_notify_send_with_data(struct peer *peer, uint8_t code, + uint8_t sub_code, uint8_t *data, + size_t datalen); void bgp_notify_io_invalid(struct peer *peer, uint8_t code, uint8_t sub_code, uint8_t *data, size_t datalen); extern void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, uint8_t orf_type, uint8_t when_to_refresh, int remove, uint8_t subtype); -extern void bgp_capability_send(struct peer *, afi_t, safi_t, int, int); +extern void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, + int capabilty_code, int action); -extern int bgp_capability_receive(struct peer *, bgp_size_t); +extern int bgp_capability_receive(struct peer *peer, bgp_size_t length); -extern int bgp_nlri_parse(struct peer *, struct attr *, struct bgp_nlri *, - int mp_withdraw); +extern int bgp_nlri_parse(struct peer *peer, struct attr *attr, + struct bgp_nlri *nlri, bool mp_withdraw); -extern void bgp_update_restarted_peers(struct peer *); -extern void bgp_update_implicit_eors(struct peer *); -extern void bgp_check_update_delay(struct bgp *); +extern void bgp_update_restarted_peers(struct peer *peer); +extern void bgp_update_implicit_eors(struct peer *peer); +extern void bgp_check_update_delay(struct bgp *peer); extern int bgp_packet_set_marker(struct stream *s, uint8_t type); extern void bgp_packet_set_size(struct stream *s); diff -Nru frr-8.4.2/bgpd/bgp_route.c frr-8.4.4/bgpd/bgp_route.c --- frr-8.4.2/bgpd/bgp_route.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_route.c 2023-06-16 04:41:18.000000000 +0000 @@ -1142,9 +1142,18 @@ /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - if ((new->extra &&bgp_is_valid_label(&new->extra->label[0])) - != (exist->extra - && bgp_is_valid_label(&exist->extra->label[0]))) { + int newl, existl; + + newl = existl = 0; + + if (new->extra) + newl = new->extra->num_labels; + if (exist->extra) + existl = exist->extra->num_labels; + if (((new->extra &&bgp_is_valid_label(&new->extra->label[0])) != + (exist->extra && + bgp_is_valid_label(&exist->extra->label[0]))) || + (newl != existl)) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", @@ -2292,7 +2301,10 @@ if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( "%pBP [Update:SEND] %pFX is filtered by route-map '%s'", - peer, p, ROUTE_MAP_OUT_NAME(filter)); + peer, p, + bgp_path_suppressed(pi) + ? UNSUPPRESS_MAP_NAME(filter) + : ROUTE_MAP_OUT_NAME(filter)); bgp_attr_flush(rmap_path.attr); return false; } @@ -2590,9 +2602,12 @@ continue; if (BGP_PATH_HOLDDOWN(pi1)) continue; - if (pi1->peer != bgp->peer_self) + if (pi1->peer != bgp->peer_self && + !CHECK_FLAG(pi1->peer->sflags, + PEER_STATUS_NSF_WAIT)) { if (!peer_established(pi1->peer)) continue; + } new_select = pi1; if (pi1->next) { @@ -3895,17 +3910,24 @@ if (has_valid_label) assert(label != NULL); - /* Update overlay index of the attribute */ - if (afi == AFI_L2VPN && evpn) - memcpy(&attr->evpn_overlay, evpn, - sizeof(struct bgp_route_evpn)); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ - if (!soft_reconfig - && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) - && peer != bgp->peer_self) + if (!soft_reconfig && + CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && + peer != bgp->peer_self) { + /* + * If the trigger is not from soft_reconfig and if + * PEER_FLAG_SOFT_RECONFIG is enabled for the peer, then attr + * will not be interned. In which case, it is ok to update the + * attr->evpn_overlay, so that, this can be stored in adj_in. + */ + if ((afi == AFI_L2VPN) && evpn) { + memcpy(&attr->evpn_overlay, evpn, + sizeof(struct bgp_route_evpn)); + } bgp_adj_in_set(dest, peer, attr, addpath_id); + } /* Check previously received route. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) @@ -4015,6 +4037,15 @@ } new_attr = *attr; + /* + * If bgp_update is called with soft_reconfig set then + * attr is interned. In this case, do not overwrite the + * attr->evpn_overlay with evpn directly. Instead memcpy + * evpn to new_atr.evpn_overlay before it is interned. + */ + if (soft_reconfig && (afi == AFI_L2VPN) && evpn) + memcpy(&new_attr.evpn_overlay, evpn, + sizeof(struct bgp_route_evpn)); /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map @@ -8182,59 +8213,7 @@ /* Unlock aggregate address configuration. */ bgp_dest_set_bgp_aggregate_info(dest, NULL); - if (aggregate->community) - community_free(&aggregate->community); - - if (aggregate->community_hash) { - /* Delete all communities in the hash. - */ - hash_clean(aggregate->community_hash, - bgp_aggr_community_remove); - /* Free up the community_hash. - */ - hash_free(aggregate->community_hash); - } - - if (aggregate->ecommunity) - ecommunity_free(&aggregate->ecommunity); - - if (aggregate->ecommunity_hash) { - /* Delete all ecommunities in the hash. - */ - hash_clean(aggregate->ecommunity_hash, - bgp_aggr_ecommunity_remove); - /* Free up the ecommunity_hash. - */ - hash_free(aggregate->ecommunity_hash); - } - - if (aggregate->lcommunity) - lcommunity_free(&aggregate->lcommunity); - - if (aggregate->lcommunity_hash) { - /* Delete all lcommunities in the hash. - */ - hash_clean(aggregate->lcommunity_hash, - bgp_aggr_lcommunity_remove); - /* Free up the lcommunity_hash. - */ - hash_free(aggregate->lcommunity_hash); - } - - if (aggregate->aspath) - aspath_free(aggregate->aspath); - - if (aggregate->aspath_hash) { - /* Delete all as-paths in the hash. - */ - hash_clean(aggregate->aspath_hash, - bgp_aggr_aspath_remove); - /* Free up the aspath_hash. - */ - hash_free(aggregate->aspath_hash); - } - - bgp_aggregate_free(aggregate); + bgp_free_aggregate_info(aggregate); bgp_dest_unlock_node(dest); bgp_dest_unlock_node(dest); @@ -8415,6 +8394,63 @@ match_med != NULL, suppress_map); } +void bgp_free_aggregate_info(struct bgp_aggregate *aggregate) +{ + if (aggregate->community) + community_free(&aggregate->community); + + if (aggregate->community_hash) { + /* Delete all communities in the hash. + */ + hash_clean(aggregate->community_hash, + bgp_aggr_community_remove); + /* Free up the community_hash. + */ + hash_free(aggregate->community_hash); + } + + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + if (aggregate->ecommunity_hash) { + /* Delete all ecommunities in the hash. + */ + hash_clean(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_remove); + /* Free up the ecommunity_hash. + */ + hash_free(aggregate->ecommunity_hash); + } + + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + if (aggregate->lcommunity_hash) { + /* Delete all lcommunities in the hash. + */ + hash_clean(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_remove); + /* Free up the lcommunity_hash. + */ + hash_free(aggregate->lcommunity_hash); + } + + if (aggregate->aspath) + aspath_free(aggregate->aspath); + + if (aggregate->aspath_hash) { + /* Delete all as-paths in the hash. + */ + hash_clean(aggregate->aspath_hash, + bgp_aggr_aspath_remove); + /* Free up the aspath_hash. + */ + hash_free(aggregate->aspath_hash); + } + + bgp_aggregate_free(aggregate); +} + DEFPY(aggregate_addressv6, aggregate_addressv6_cmd, "[no] aggregate-address X:X::X:X/M$prefix [{" "as-set$as_set_s" @@ -11416,7 +11452,16 @@ else vty_out(vty, ",\"%pFX\": ", dest_p); } - vty_json(vty, json_paths); + /* + * We are using no_pretty here because under + * extremely high settings( say lots and lots of + * routes with lots and lots of ways to reach + * that route via different paths ) this can + * save several minutes of output when FRR + * is run on older cpu's or more underperforming + * routers out there + */ + vty_json_no_pretty(vty, json_paths); json_paths = NULL; first = 0; } else @@ -11650,11 +11695,13 @@ vty_out(vty, "BGP routing table entry for %s%s%pFX, version %" PRIu64 "\n", - ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + (((safi == SAFI_MPLS_VPN || + safi == SAFI_ENCAP) && + prd) ? prefix_rd2str(prd, buf1, sizeof(buf1)) : ""), - safi == SAFI_MPLS_VPN ? ":" : "", p, + safi == SAFI_MPLS_VPN && prd ? ":" : "", p, dest->version); } else { diff -Nru frr-8.4.2/bgpd/bgp_route.h frr-8.4.4/bgpd/bgp_route.h --- frr-8.4.2/bgpd/bgp_route.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_route.h 2023-06-16 04:41:18.000000000 +0000 @@ -667,6 +667,7 @@ extern void bgp_route_init(void); extern void bgp_route_finish(void); extern void bgp_cleanup_routes(struct bgp *); +extern void bgp_free_aggregate_info(struct bgp_aggregate *aggregate); extern void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force); extern void bgp_stop_announce_route_timer(struct peer_af *paf); diff -Nru frr-8.4.2/bgpd/bgp_updgrp_adv.c frr-8.4.4/bgpd/bgp_updgrp_adv.c --- frr-8.4.2/bgpd/bgp_updgrp_adv.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_updgrp_adv.c 2023-06-16 04:41:18.000000000 +0000 @@ -507,6 +507,23 @@ zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host, attr_str); } + + /* + * If BGP is skipping sending this value to it's peers + * the version number should be updated just like it + * would if it sent the data. Why? Because update + * groups will not be coalesced until such time that + * the version numbers are the same. + * + * Imagine a scenario with say 2 peers and they come + * up and are placed in the same update group. Then + * a new peer comes up a bit later. Then a prefix is + * flapped that we decide for the first 2 peers are + * mapped to and we decide not to send the data to + * it. Then unless more network changes happen we + * will never be able to coalesce the 3rd peer down + */ + subgrp->version = MAX(subgrp->version, dest->version); return; } @@ -918,10 +935,14 @@ if (subgroup_announce_check( dest, pi, subgrp, bgp_dest_get_prefix(dest), - &attr, NULL)) + &attr, NULL)) { + struct attr *default_attr = + bgp_attr_intern(&attr); + bgp_adj_out_set_subgroup( - dest, subgrp, &attr, - pi); + dest, subgrp, + default_attr, pi); + } } bgp_dest_unlock_node(dest); } diff -Nru frr-8.4.2/bgpd/bgp_vty.c frr-8.4.4/bgpd/bgp_vty.c --- frr-8.4.2/bgpd/bgp_vty.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgp_vty.c 2023-06-16 04:41:18.000000000 +0000 @@ -1573,28 +1573,46 @@ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; - if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], - BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + if (CHECK_FLAG( + tmp_bgp->af_flags[AFI_IP] + [SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_IP6] + [SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_IP] + [SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_IP6] + [SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP] + [SAFI_UNICAST], BGP_CONFIG_VRF_TO_VRF_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6] + [SAFI_UNICAST], BGP_CONFIG_VRF_TO_VRF_EXPORT) || (bgp == bgp_get_evpn() && - (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADV_IPV4_UNICAST) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADV_IPV6_UNICAST) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) || - (hashcount(tmp_bgp->vnihash))) { + (CHECK_FLAG( + tmp_bgp->af_flags[AFI_L2VPN] + [SAFI_EVPN], + BGP_L2VPN_EVPN_ADV_IPV4_UNICAST) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_L2VPN] + [SAFI_EVPN], + BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_L2VPN] + [SAFI_EVPN], + BGP_L2VPN_EVPN_ADV_IPV6_UNICAST) || + CHECK_FLAG( + tmp_bgp->af_flags[AFI_L2VPN] + [SAFI_EVPN], + BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) || + (tmp_bgp->l3vni)) { vty_out(vty, "%% Cannot delete default BGP instance. Dependent VRF instances exist\n"); return CMD_WARNING_CONFIG_FAILED; diff -Nru frr-8.4.2/bgpd/bgpd.c frr-8.4.4/bgpd/bgpd.c --- frr-8.4.2/bgpd/bgpd.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/bgpd.c 2023-06-16 04:41:18.000000000 +0000 @@ -1461,9 +1461,11 @@ peer_dst->v_delayopen = peer_src->v_delayopen; /* password apply */ - if (peer_src->password && !peer_dst->password) + if (peer_src->password) { + XFREE(MTYPE_PEER_PASSWORD, peer_dst->password); peer_dst->password = XSTRDUP(MTYPE_PEER_PASSWORD, peer_src->password); + } FOREACH_AFI_SAFI (afi, safi) { peer_dst->afc[afi][safi] = peer_src->afc[afi][safi]; @@ -1959,9 +1961,9 @@ /* If the peer is not part of our confederation, and its not an iBGP peer then spoof the source AS */ - if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) - && !bgp_confederation_peers_check(bgp, *as) - && bgp->as != *as) + if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) && + !bgp_confederation_peers_check(bgp, *as) && *as && + bgp->as != *as) local_as = bgp->confed_id; else local_as = bgp->as; @@ -3722,6 +3724,23 @@ #ifdef ENABLE_BGP_VNC rfapi_delete(bgp); #endif + + /* Free memory allocated with aggregate address configuration. */ + FOREACH_AFI_SAFI (afi, safi) { + struct bgp_aggregate *aggregate = NULL; + + for (struct bgp_dest *dest = + bgp_table_top(bgp->aggregate[afi][safi]); + dest; dest = bgp_route_next(dest)) { + aggregate = bgp_dest_get_bgp_aggregate_info(dest); + if (aggregate == NULL) + continue; + + bgp_dest_set_bgp_aggregate_info(dest, NULL); + bgp_free_aggregate_info(aggregate); + } + } + bgp_cleanup_routes(bgp); for (afi = 0; afi < AFI_MAX; ++afi) { @@ -5500,23 +5519,12 @@ return; if (CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_SOFT_RECONFIG)) { + PEER_FLAG_SOFT_RECONFIG)) bgp_soft_reconfig_in(peer, afi, safi); - } else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV) || - CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) { - 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_clear_soft(peer, afi, safi, - BGP_CLEAR_SOFT_IN_ORF_PREFIX); - else - bgp_route_refresh_send( - peer, afi, safi, 0, 0, 0, - BGP_ROUTE_REFRESH_NORMAL); - } + else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV) || + CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) + bgp_route_refresh_send(peer, afi, safi, 0, 0, 0, + BGP_ROUTE_REFRESH_NORMAL); } } @@ -6770,11 +6778,18 @@ /* If we touch prefix-list, we need to process * new updates. This is important for ORF to - * work correctly as well. + * work correctly. */ - if (peer->afc_nego[afi][safi]) - peer_on_policy_change(peer, afi, safi, - 0); + 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_clear_soft( + peer, afi, safi, + BGP_CLEAR_SOFT_IN_ORF_PREFIX); } } for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { diff -Nru frr-8.4.2/bgpd/rfapi/rfapi_import.c frr-8.4.4/bgpd/rfapi/rfapi_import.c --- frr-8.4.2/bgpd/rfapi/rfapi_import.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/bgpd/rfapi/rfapi_import.c 2023-06-16 04:41:18.000000000 +0000 @@ -2344,8 +2344,7 @@ } /* - * quagga lib/thread.h says this must return int even though - * it doesn't do anything with the return value + * Timer callback for withdraw */ static void rfapiWithdrawTimerVPN(struct thread *t) { @@ -2355,19 +2354,27 @@ const struct prefix *p; struct rfapi_monitor_vpn *moved; afi_t afi; + bool early_exit = false; if (bgp == NULL) { vnc_zlog_debug_verbose( "%s: NULL BGP pointer, assume shutdown race condition!!!", __func__); - return; + early_exit = true; } - if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { + if (bgp && CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { vnc_zlog_debug_verbose( "%s: BGP delete in progress, assume shutdown race condition!!!", __func__); + early_exit = true; + } + + /* This callback is responsible for the withdraw object's memory */ + if (early_exit) { + XFREE(MTYPE_RFAPI_WITHDRAW, wcb); return; } + assert(wcb->node); assert(bpi); assert(wcb->import_table); diff -Nru frr-8.4.2/configure.ac frr-8.4.4/configure.ac --- frr-8.4.2/configure.ac 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/configure.ac 2023-06-16 04:41:18.000000000 +0000 @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [8.4.2], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [8.4.4], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" diff -Nru frr-8.4.2/debian/changelog frr-8.4.4/debian/changelog --- frr-8.4.2/debian/changelog 2023-01-23 16:32:02.000000000 +0000 +++ frr-8.4.4/debian/changelog 2023-09-05 08:04:06.000000000 +0000 @@ -1,3 +1,27 @@ +frr (8.4.4-1.1~deb12u1) bookworm-security; urgency=high + + * Non-maintainer upload by the Security Team. + * Update to upstream 8.4.4 stable point release. + + -- Aron Xu Tue, 05 Sep 2023 16:04:06 +0800 + +frr (8.4.4-1.1) unstable; urgency=high + + * Non-maintainer upload by the Security Team. + * Upstream fixes for CVE-2023-38802, CVE-2023-41358, CVE-2023-41360 + + -- Aron Xu Fri, 01 Sep 2023 16:57:41 +0800 + +frr (8.4.4-1) unstable; urgency=medium + + * new upstream release FRR 8.4.4 + * upstream fix CVE-2023-31489 (closes: #1036061) + * upstream fix CVE-2023-31490 (closes: #1036062) + * correctly use sphinxdoc:Built-Using + * point watch file at git tarball, no more upstream dist tarballs + + -- David Lamparter Wed, 12 Jul 2023 14:28:34 +0200 + frr (8.4.2-1) unstable; urgency=medium * new upstream release FRR 8.4.2 diff -Nru frr-8.4.2/debian/control frr-8.4.4/debian/control --- frr-8.4.2/debian/control 2023-01-19 03:57:31.000000000 +0000 +++ frr-8.4.4/debian/control 2023-07-12 12:28:34.000000000 +0000 @@ -106,6 +106,7 @@ Multi-Arch: foreign Depends: ${misc:Depends}, ${sphinxdoc:Depends} +Built-Using: ${sphinxdoc:Built-Using} Suggests: frr Conflicts: quagga-doc Description: FRRouting suite - user manual diff -Nru frr-8.4.2/debian/gbp.conf frr-8.4.4/debian/gbp.conf --- frr-8.4.2/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/gbp.conf 2023-07-12 12:28:34.000000000 +0000 @@ -0,0 +1,7 @@ +[DEFAULT] +upstream-tag = frr-%(version)s +pristine-tar = False + +[export-orig] +compression = xz + diff -Nru frr-8.4.2/debian/patches/CVE-2023-38802.patch frr-8.4.4/debian/patches/CVE-2023-38802.patch --- frr-8.4.2/debian/patches/CVE-2023-38802.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2023-38802.patch 2023-09-01 08:51:51.000000000 +0000 @@ -0,0 +1,131 @@ +From bcb6b58d9530173df41d3a3cbc4c600ee0b4b186 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Thu, 13 Jul 2023 22:32:03 +0300 +Subject: [PATCH] bgpd: Use treat-as-withdraw for tunnel encapsulation + attribute + +Before this path we used session reset method, which is discouraged by rfc7606. + +Handle this as rfc requires. + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_attr.c | 61 ++++++++++++++++++++----------------------------- + 1 file changed, 25 insertions(+), 36 deletions(-) + +diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c +index dcf0f4d47..8c53191d6 100644 +--- a/bgpd/bgp_attr.c ++++ b/bgpd/bgp_attr.c +@@ -1405,6 +1405,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, + case BGP_ATTR_LARGE_COMMUNITIES: + case BGP_ATTR_ORIGINATOR_ID: + case BGP_ATTR_CLUSTER_LIST: ++ case BGP_ATTR_ENCAP: + case BGP_ATTR_OTC: + return BGP_ATTR_PARSE_WITHDRAW; + case BGP_ATTR_MP_REACH_NLRI: +@@ -2635,26 +2636,21 @@ ipv6_ext_community_ignore: + } + + /* Parse Tunnel Encap attribute in an UPDATE */ +-static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ +- bgp_size_t length, /* IN: attr's length field */ +- struct attr *attr, /* IN: caller already allocated */ +- uint8_t flag, /* IN: attr's flags field */ +- uint8_t *startp) ++static int bgp_attr_encap(struct bgp_attr_parser_args *args) + { +- bgp_size_t total; + uint16_t tunneltype = 0; +- +- total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); ++ struct peer *const peer = args->peer; ++ struct attr *const attr = args->attr; ++ bgp_size_t length = args->length; ++ uint8_t type = args->type; ++ uint8_t flag = args->flags; + + if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) + || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) { +- zlog_info( +- "Tunnel Encap attribute flag isn't optional and transitive %d", +- flag); +- bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, +- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, +- startp, total); +- return -1; ++ zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d", ++ flag); ++ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, ++ args->total); + } + + if (BGP_ATTR_ENCAP == type) { +@@ -2662,12 +2658,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ + uint16_t tlv_length; + + if (length < 4) { +- zlog_info( ++ zlog_err( + "Tunnel Encap attribute not long enough to contain outer T,L"); +- bgp_notify_send_with_data( +- peer, BGP_NOTIFY_UPDATE_ERR, +- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); +- return -1; ++ return bgp_attr_malformed(args, ++ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, ++ args->total); + } + tunneltype = stream_getw(BGP_INPUT(peer)); + tlv_length = stream_getw(BGP_INPUT(peer)); +@@ -2699,13 +2694,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ + } + + if (sublength > length) { +- zlog_info( +- "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", +- sublength, length); +- bgp_notify_send_with_data( +- peer, BGP_NOTIFY_UPDATE_ERR, +- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); +- return -1; ++ zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", ++ sublength, length); ++ return bgp_attr_malformed(args, ++ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, ++ args->total); + } + + /* alloc and copy sub-tlv */ +@@ -2753,13 +2746,10 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ + + if (length) { + /* spurious leftover data */ +- zlog_info( +- "Tunnel Encap attribute length is bad: %d leftover octets", +- length); +- bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, +- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, +- startp, total); +- return -1; ++ zlog_err("Tunnel Encap attribute length is bad: %d leftover octets", ++ length); ++ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, ++ args->total); + } + + return 0; +@@ -3732,8 +3722,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, + case BGP_ATTR_VNC: + #endif + case BGP_ATTR_ENCAP: +- ret = bgp_attr_encap(type, peer, length, attr, flag, +- startp); ++ ret = bgp_attr_encap(&attr_args); + break; + case BGP_ATTR_PREFIX_SID: + ret = bgp_attr_prefix_sid(&attr_args); +-- +2.39.2 + diff -Nru frr-8.4.2/debian/patches/CVE-2023-41358.patch frr-8.4.4/debian/patches/CVE-2023-41358.patch --- frr-8.4.2/debian/patches/CVE-2023-41358.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2023-41358.patch 2023-09-01 08:53:05.000000000 +0000 @@ -0,0 +1,100 @@ +From f291f1ee9434f56d4b185db0652794a92e313b00 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Tue, 22 Aug 2023 22:52:04 +0300 +Subject: [PATCH] bgpd: Do not process NLRIs if the attribute length is zero + +``` +3 0x00007f423aa42476 in __GI_raise (sig=sig@entry=11) at ../sysdeps/posix/raise.c:26 +4 0x00007f423aef9740 in core_handler (signo=11, siginfo=0x7fffc414deb0, context=) at lib/sigevent.c:246 +5 +6 0x0000564dea2fc71e in route_set_aspath_prepend (rule=0x564debd66d50, prefix=0x7fffc414ea30, object=0x7fffc414e400) + at bgpd/bgp_routemap.c:2258 +7 0x00007f423aeec7e0 in route_map_apply_ext (map=, prefix=prefix@entry=0x7fffc414ea30, + match_object=match_object@entry=0x7fffc414e400, set_object=set_object@entry=0x7fffc414e400, pref=pref@entry=0x0) at lib/routemap.c:2690 +8 0x0000564dea2d277e in bgp_input_modifier (peer=peer@entry=0x7f4238f59010, p=p@entry=0x7fffc414ea30, attr=attr@entry=0x7fffc414e770, + afi=afi@entry=AFI_IP, safi=safi@entry=SAFI_UNICAST, rmap_name=rmap_name@entry=0x0, label=0x0, num_labels=0, dest=0x564debdd5130) + at bgpd/bgp_route.c:1772 +9 0x0000564dea2df762 in bgp_update (peer=peer@entry=0x7f4238f59010, p=p@entry=0x7fffc414ea30, addpath_id=addpath_id@entry=0, + attr=0x7fffc414eb50, afi=afi@entry=AFI_IP, safi=, safi@entry=SAFI_UNICAST, type=9, sub_type=0, prd=0x0, label=0x0, + num_labels=0, soft_reconfig=0, evpn=0x0) at bgpd/bgp_route.c:4374 +10 0x0000564dea2e2047 in bgp_nlri_parse_ip (peer=0x7f4238f59010, attr=attr@entry=0x7fffc414eb50, packet=0x7fffc414eaf0) + at bgpd/bgp_route.c:6249 +11 0x0000564dea2c5a58 in bgp_nlri_parse (peer=peer@entry=0x7f4238f59010, attr=attr@entry=0x7fffc414eb50, + packet=packet@entry=0x7fffc414eaf0, mp_withdraw=mp_withdraw@entry=false) at bgpd/bgp_packet.c:339 +12 0x0000564dea2c5d66 in bgp_update_receive (peer=peer@entry=0x7f4238f59010, size=size@entry=109) at bgpd/bgp_packet.c:2024 +13 0x0000564dea2c901d in bgp_process_packet (thread=) at bgpd/bgp_packet.c:2933 +14 0x00007f423af0bf71 in event_call (thread=thread@entry=0x7fffc414ee40) at lib/event.c:1995 +15 0x00007f423aebb198 in frr_run (master=0x564deb73c670) at lib/libfrr.c:1213 +16 0x0000564dea261b83 in main (argc=, argv=) at bgpd/bgp_main.c:505 +``` + +With the configuration: + +``` +frr version 9.1-dev-MyOwnFRRVersion +frr defaults traditional +hostname ip-172-31-13-140 +log file /tmp/debug.log +log syslog +service integrated-vtysh-config +! +debug bgp keepalives +debug bgp neighbor-events +debug bgp updates in +debug bgp updates out +! +router bgp 100 + bgp router-id 9.9.9.9 + no bgp ebgp-requires-policy + bgp bestpath aigp + neighbor 172.31.2.47 remote-as 200 + ! + address-family ipv4 unicast + neighbor 172.31.2.47 default-originate + neighbor 172.31.2.47 route-map RM_IN in + exit-address-family +exit +! +route-map RM_IN permit 10 + set as-path prepend 200 +exit +! +``` + +The issue is that we try to process NLRIs even if the attribute length is 0. + +Later bgp_update() will handle route-maps and a crash occurs because all the +attributes are NULL, including aspath, where we dereference. + +According to the RFC 4271: + +A value of 0 indicates that neither the Network Layer + Reachability Information field nor the Path Attribute field is + present in this UPDATE message. + +But with a fuzzed UPDATE message this can be faked. I think it's reasonable +to skip processing NLRIs if both update_len and attribute_len are 0. + +Reported-by: Iggy Frankovic +Signed-off-by: Donatas Abraitis +(cherry picked from commit 28ccc24d38df1d51ed8a563507e5d6f6171fdd38) +--- + bgpd/bgp_packet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index 60f1dcbcd..a02d54894 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -1983,7 +1983,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) + /* Network Layer Reachability Information. */ + update_len = end - stream_pnt(s); + +- if (update_len) { ++ if (update_len && attribute_len) { + /* Set NLRI portion to structure. */ + nlris[NLRI_UPDATE].afi = AFI_IP; + nlris[NLRI_UPDATE].safi = SAFI_UNICAST; +-- +2.39.2 + diff -Nru frr-8.4.2/debian/patches/CVE-2023-41360.patch frr-8.4.4/debian/patches/CVE-2023-41360.patch --- frr-8.4.2/debian/patches/CVE-2023-41360.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2023-41360.patch 2023-09-01 08:54:39.000000000 +0000 @@ -0,0 +1,30 @@ +From 3515178de4a56d66ed948a774efcbe4a854e1ca7 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Sun, 20 Aug 2023 22:15:27 +0300 +Subject: [PATCH] bgpd: Don't read the first byte of ORF header if we are ahead + of stream + +Reported-by: Iggy Frankovic iggyfran@amazon.com +Signed-off-by: Donatas Abraitis +(cherry picked from commit 9b855a692e68e0d16467e190b466b4ecb6853702) +--- + bgpd/bgp_packet.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index a2959ef6e..60f1dcbcd 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -2408,7 +2408,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) + * and 7 bytes of ORF Address-filter entry from + * the stream + */ +- if (*p_pnt & ORF_COMMON_PART_REMOVE_ALL) { ++ if (p_pnt < p_end && ++ *p_pnt & ORF_COMMON_PART_REMOVE_ALL) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%pBP rcvd Remove-All pfxlist ORF request", +-- +2.39.2 + diff -Nru frr-8.4.2/debian/patches/CVE-2023-41361.patch frr-8.4.4/debian/patches/CVE-2023-41361.patch --- frr-8.4.2/debian/patches/CVE-2023-41361.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2023-41361.patch 2023-09-01 08:56:12.000000000 +0000 @@ -0,0 +1,43 @@ +From 73ad93a83f18564bb7bff4659872f7ec1a64b05e Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Sun, 20 Aug 2023 21:37:25 +0300 +Subject: [PATCH] bgpd: Check the length of the rcv software version + +Make sure we don't exceed the maximum of BGP_MAX_SOFT_VERSION. + +The Capability Length SHOULD be no greater than 64. + +Reported-by: Iggy Frankovic +Signed-off-by: Donatas Abraitis +(cherry picked from commit b4d09af9194d20a7f9f16995a062f5d8e3d32840) +--- + bgpd/bgp_open.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c +index 0dd546397..e7e3c2191 100644 +--- a/bgpd/bgp_open.c ++++ b/bgpd/bgp_open.c +@@ -940,8 +940,18 @@ static int bgp_capability_software_version(struct peer *peer, + return -1; + } + +- if (len) { ++ if (len > BGP_MAX_SOFT_VERSION) { ++ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, ++ "%s: Received Software Version, but the length is too big, truncating, from peer %s", ++ __func__, peer->host); ++ stream_get(str, s, BGP_MAX_SOFT_VERSION); ++ stream_forward_getp(s, len - BGP_MAX_SOFT_VERSION); ++ len = BGP_MAX_SOFT_VERSION; ++ } else if (len) { + stream_get(str, s, len); ++ } ++ ++ if (len) { + str[len] = '\0'; + + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); +-- +2.39.2 + diff -Nru frr-8.4.2/debian/patches/series frr-8.4.4/debian/patches/series --- frr-8.4.2/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/series 2023-09-01 08:56:56.000000000 +0000 @@ -0,0 +1,3 @@ +CVE-2023-38802.patch +CVE-2023-41358.patch +CVE-2023-41360.patch diff -Nru frr-8.4.2/debian/watch frr-8.4.4/debian/watch --- frr-8.4.2/debian/watch 2023-01-19 03:57:31.000000000 +0000 +++ frr-8.4.4/debian/watch 2023-07-12 12:28:34.000000000 +0000 @@ -3,8 +3,8 @@ opts="\ searchmode=plain,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,\ -downloadurlmangle=s&>FRR\s*(\d\S+)\s+Release<&download/frr-$1/frr-$1.tar.xz&,\ -filenamemangle=s&>FRR\s*(\d\S+)\s+Release<&frr-$1.tar.xz&,\ +downloadurlmangle=s&releases/>FRR\s*(\d\S+)\s+Release<&archive/refs/tags/frr-$1.tar.gz&,\ +filenamemangle=s&>FRR\s*(\d\S+)\s+Release<&frr-$1.tar.gz&,\ " \ https://github.com/FRRouting/frr/releases/ \ >FRR\s*(\d\S+)\s+Release< diff -Nru frr-8.4.2/lib/bfd.c frr-8.4.4/lib/bfd.c --- frr-8.4.2/lib/bfd.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/bfd.c 2023-06-16 04:41:18.000000000 +0000 @@ -508,13 +508,13 @@ static void _bfd_sess_remove(struct bfd_session_params *bsp) { + /* Cancel any pending installation request. */ + THREAD_OFF(bsp->installev); + /* Not installed, nothing to do. */ if (!bsp->installed) return; - /* Cancel any pending installation request. */ - THREAD_OFF(bsp->installev); - /* Send request to remove any session. */ bsp->lastev = BSE_UNINSTALL; thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); diff -Nru frr-8.4.2/lib/command.c frr-8.4.4/lib/command.c --- frr-8.4.2/lib/command.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/command.c 2023-06-16 04:41:18.000000000 +0000 @@ -743,9 +743,13 @@ char *item = vector_slot(comps, j); itemlen = strlen(item); - if (cs + itemlen + AUTOCOMP_INDENT + 3 >= bsz) - buf = XREALLOC(MTYPE_TMP, buf, (bsz *= 2)); + size_t next_sz = cs + itemlen + AUTOCOMP_INDENT + 3; + if (next_sz > bsz) { + /* Make sure the buf size is large enough */ + bsz = next_sz; + buf = XREALLOC(MTYPE_TMP, buf, bsz); + } if (lc + itemlen + 1 >= cols) { cs += snprintf(&buf[cs], bsz - cs, "\n%*s", AUTOCOMP_INDENT, ""); diff -Nru frr-8.4.2/lib/filter_cli.c frr-8.4.4/lib/filter_cli.c --- frr-8.4.2/lib/filter_cli.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/filter_cli.c 2023-06-16 04:41:18.000000000 +0000 @@ -1319,6 +1319,7 @@ vty, "./ipv4-prefix-length-lesser-or-equal", NB_OP_DESTROY, NULL); } + nb_cli_enqueue_change(vty, "./any", NB_OP_DESTROY, NULL); } else { nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL); } @@ -1520,6 +1521,7 @@ vty, "./ipv6-prefix-length-lesser-or-equal", NB_OP_DESTROY, NULL); } + nb_cli_enqueue_change(vty, "./any", NB_OP_DESTROY, NULL); } else { nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL); } diff -Nru frr-8.4.2/lib/filter_nb.c frr-8.4.4/lib/filter_nb.c --- frr-8.4.2/lib/filter_nb.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/filter_nb.c 2023-06-16 04:41:18.000000000 +0000 @@ -1643,7 +1643,7 @@ /* Start prefix entry update procedure. */ prefix_list_entry_update_start(ple); - prefix_list_entry_set_empty(ple); + ple->any = false; /* Finish prefix entry update procedure. */ prefix_list_entry_update_finish(ple); diff -Nru frr-8.4.2/lib/if_rmap.c frr-8.4.4/lib/if_rmap.c --- frr-8.4.2/lib/if_rmap.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/if_rmap.c 2023-06-16 04:41:18.000000000 +0000 @@ -293,7 +293,7 @@ listnode_delete(if_rmap_ctx_list, ctx); hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free); if (ctx->name) - XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx); + XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx->name); XFREE(MTYPE_IF_RMAP_CTX, ctx); } diff -Nru frr-8.4.2/lib/link_state.c frr-8.4.4/lib/link_state.c --- frr-8.4.2/lib/link_state.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/link_state.c 2023-06-16 04:41:18.000000000 +0000 @@ -1888,6 +1888,20 @@ if (msg == NULL) return; + if (msg->event == LS_MSG_EVENT_DELETE) { + switch (msg->type) { + case LS_MSG_TYPE_NODE: + ls_node_del(msg->data.node); + break; + case LS_MSG_TYPE_ATTRIBUTES: + ls_attributes_del(msg->data.attr); + break; + case LS_MSG_TYPE_PREFIX: + ls_prefix_del(msg->data.prefix); + break; + } + } + XFREE(MTYPE_LS_DB, msg); } diff -Nru frr-8.4.2/lib/vty.c frr-8.4.4/lib/vty.c --- frr-8.4.2/lib/vty.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/vty.c 2023-06-16 04:41:18.000000000 +0000 @@ -281,7 +281,8 @@ return len; } -int vty_json(struct vty *vty, struct json_object *json) +static int vty_json_helper(struct vty *vty, struct json_object *json, + uint32_t options) { const char *text; @@ -289,13 +290,25 @@ return CMD_SUCCESS; text = json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE); + json, options); vty_out(vty, "%s\n", text); json_object_free(json); return CMD_SUCCESS; } +int vty_json(struct vty *vty, struct json_object *json) +{ + return vty_json_helper(vty, json, + JSON_C_TO_STRING_PRETTY | + JSON_C_TO_STRING_NOSLASHESCAPE); +} + +int vty_json_no_pretty(struct vty *vty, struct json_object *json) +{ + return vty_json_helper(vty, json, JSON_C_TO_STRING_NOSLASHESCAPE); +} + /* Output current time to the vty. */ void vty_time_print(struct vty *vty, int cr) { diff -Nru frr-8.4.2/lib/vty.h frr-8.4.4/lib/vty.h --- frr-8.4.2/lib/vty.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/vty.h 2023-06-16 04:41:18.000000000 +0000 @@ -348,8 +348,12 @@ extern bool vty_set_include(struct vty *vty, const char *regexp); /* returns CMD_SUCCESS so you can do a one-line "return vty_json(...)" * NULL check and json_object_free() is included. + * + * _no_pretty means do not add a bunch of newlines and dump the output + * as densely as possible. */ extern int vty_json(struct vty *vty, struct json_object *json); +extern int vty_json_no_pretty(struct vty *vty, struct json_object *json); /* post fd to be passed to the vtysh client * fd is owned by the VTY code after this and will be closed when done diff -Nru frr-8.4.2/lib/yang_translator.c frr-8.4.4/lib/yang_translator.c --- frr-8.4.2/lib/yang_translator.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/lib/yang_translator.c 2023-06-16 04:41:18.000000000 +0000 @@ -127,10 +127,15 @@ } } +static void yang_tmodule_delete(struct yang_tmodule *tmodule) +{ + XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule); +} + struct yang_translator *yang_translator_load(const char *path) { struct yang_translator *translator; - struct yang_tmodule *tmodule; + struct yang_tmodule *tmodule = NULL; const char *family; struct lyd_node *dnode; struct ly_set *set; @@ -160,6 +165,7 @@ flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, "%s: module translator \"%s\" is loaded already", __func__, family); + yang_dnode_free(dnode); return NULL; } @@ -282,15 +288,11 @@ error: yang_dnode_free(dnode); yang_translator_unload(translator); + yang_tmodule_delete(tmodule); return NULL; } -static void yang_tmodule_delete(struct yang_tmodule *tmodule) -{ - XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule); -} - void yang_translator_unload(struct yang_translator *translator) { for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++) diff -Nru frr-8.4.2/ospf6d/ospf6_flood.c frr-8.4.4/ospf6d/ospf6_flood.c --- frr-8.4.2/ospf6d/ospf6_flood.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospf6d/ospf6_flood.c 2023-06-16 04:41:18.000000000 +0000 @@ -936,7 +936,11 @@ /* (1) LSA Checksum */ if (!ospf6_lsa_checksum_valid(new->header)) { if (is_debug) - zlog_debug("Wrong LSA Checksum, discard"); + zlog_debug( + "Wrong LSA Checksum %s (Router-ID: %pI4) [Type:%s Checksum:%#06hx), discard", + from->name, &from->router_id, + ospf6_lstype_name(new->header->type), + ntohs(new->header->checksum)); ospf6_lsa_delete(new); return; } diff -Nru frr-8.4.2/ospf6d/ospf6_gr_helper.c frr-8.4.4/ospf6d/ospf6_gr_helper.c --- frr-8.4.2/ospf6d/ospf6_gr_helper.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospf6d/ospf6_gr_helper.c 2023-06-16 04:41:18.000000000 +0000 @@ -297,8 +297,9 @@ if (IS_DEBUG_OSPF6_GR) zlog_debug( - "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s", - __func__, &restarter->router_id, grace_interval, + "%s, Grace LSA received from %s(%pI4), grace interval:%u, restart reason:%s", + __func__, restarter->name, &restarter->router_id, + grace_interval, ospf6_restart_reason_desc[restart_reason]); /* Verify Helper enabled globally */ diff -Nru frr-8.4.2/ospf6d/ospf6_lsa.c frr-8.4.4/ospf6d/ospf6_lsa.c --- frr-8.4.2/ospf6d/ospf6_lsa.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospf6d/ospf6_lsa.c 2023-06-16 04:41:18.000000000 +0000 @@ -575,7 +575,7 @@ json = json_object_new_object(); size_t header_str_sz = (2 * (end - start)) + 1; - header_str = XMALLOC(MTYPE_TMP, header_str_sz); + header_str = XMALLOC(MTYPE_OSPF6_LSA_HEADER, header_str_sz); inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id)); inet_ntop(AF_INET, &lsa->header->adv_router, adv_router, @@ -588,7 +588,7 @@ json_object_string_add(json, "header", header_str); json_object_array_add(json_array, json); - XFREE(MTYPE_TMP, header_str); + XFREE(MTYPE_OSPF6_LSA_HEADER, header_str); } else { vty_out(vty, "\n%s:\n", lsa->name); diff -Nru frr-8.4.2/ospf6d/ospf6_message.c frr-8.4.4/ospf6d/ospf6_message.c --- frr-8.4.2/ospf6d/ospf6_message.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospf6d/ospf6_message.c 2023-06-16 04:41:18.000000000 +0000 @@ -424,26 +424,29 @@ /* HelloInterval check */ if (ntohs(hello->hello_interval) != oi->hello_interval) { zlog_warn( - "VRF %s: I/F %s HelloInterval mismatch: (my %d, rcvd %d)", - oi->interface->vrf->name, oi->interface->name, - oi->hello_interval, ntohs(hello->hello_interval)); + "VRF %s: I/F %s HelloInterval mismatch from %pI6 (%pI4): (my %d, rcvd %d)", + oi->interface->vrf->name, oi->interface->name, src, + &oh->router_id, oi->hello_interval, + ntohs(hello->hello_interval)); return; } /* RouterDeadInterval check */ if (ntohs(hello->dead_interval) != oi->dead_interval) { zlog_warn( - "VRF %s: I/F %s DeadInterval mismatch: (my %d, rcvd %d)", - oi->interface->vrf->name, oi->interface->name, - oi->dead_interval, ntohs(hello->dead_interval)); + "VRF %s: I/F %s DeadInterval mismatch from %pI6 (%pI4): (my %d, rcvd %d)", + oi->interface->vrf->name, oi->interface->name, src, + &oh->router_id, oi->dead_interval, + ntohs(hello->dead_interval)); return; } /* E-bit check */ - if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_E) - != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_E)) { - zlog_warn("VRF %s: IF %s E-bit mismatch", - oi->interface->vrf->name, oi->interface->name); + if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_E) != + OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_E)) { + zlog_warn("VRF %s: IF %s E-bit mismatch from %pI6 (%pI4)", + oi->interface->vrf->name, oi->interface->name, src, + &oh->router_id); return; } @@ -701,8 +704,9 @@ if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) { zlog_warn( - "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)", - on->name, (unsigned long)on->dbdesc_seqnum); + "DbDesc recv: Sequence number mismatch Nbr %s (received %#lx, %#lx expected)", + on->name, (unsigned long)ntohl(dbdesc->seqnum), + (unsigned long)on->dbdesc_seqnum); thread_add_event(master, seqnumber_mismatch, on, 0, NULL); return; @@ -920,8 +924,9 @@ if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) { zlog_warn( - "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)", - on->name, (unsigned long)on->dbdesc_seqnum + 1); + "DbDesc slave recv: Sequence number mismatch Nbr %s (received %#lx, %#lx expected)", + on->name, (unsigned long)ntohl(dbdesc->seqnum), + (unsigned long)on->dbdesc_seqnum + 1); thread_add_event(master, seqnumber_mismatch, on, 0, NULL); return; @@ -1551,20 +1556,25 @@ struct ospf6_header *oh, const unsigned bytesonwire) { + struct ospf6_neighbor *on; if (MSG_OK != ospf6_packet_examin(oh, bytesonwire)) return MSG_NG; + on = ospf6_neighbor_lookup(oh->router_id, oi); + /* Area-ID check */ if (oh->area_id != oi->area->area_id) { if (oh->area_id == OSPF_AREA_BACKBONE) zlog_warn( - "VRF %s: I/F %s Message may be via Virtual Link: not supported", - oi->interface->vrf->name, oi->interface->name); + "VRF %s: I/F %s (%s, Router-ID: %pI4) Message may be via Virtual Link: not supported", + oi->interface->vrf->name, oi->interface->name, + on ? on->name : "null", &oh->router_id); else zlog_warn( - "VRF %s: I/F %s Area-ID mismatch (my %pI4, rcvd %pI4)", + "VRF %s: I/F %s (%s, Router-ID: %pI4) Area-ID mismatch (my %pI4, rcvd %pI4)", oi->interface->vrf->name, oi->interface->name, + on ? on->name : "null", &oh->router_id, &oi->area->area_id, &oh->area_id); return MSG_NG; } @@ -1572,9 +1582,10 @@ /* Instance-ID check */ if (oh->instance_id != oi->instance_id) { zlog_warn( - "VRF %s: I/F %s Instance-ID mismatch (my %u, rcvd %u)", + "VRF %s: I/F %s (%s, Router-ID: %pI4) Instance-ID mismatch (my %u, rcvd %u)", oi->interface->vrf->name, oi->interface->name, - oi->instance_id, oh->instance_id); + on ? on->name : "null", &oh->router_id, oi->instance_id, + oh->instance_id); return MSG_NG; } diff -Nru frr-8.4.2/ospf6d/ospf6_neighbor.c frr-8.4.4/ospf6d/ospf6_neighbor.c --- frr-8.4.2/ospf6d/ospf6_neighbor.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospf6d/ospf6_neighbor.c 2023-06-16 04:41:18.000000000 +0000 @@ -201,10 +201,12 @@ /* log */ if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) { - zlog_debug("Neighbor state change %s: [%s]->[%s] (%s)", - on->name, ospf6_neighbor_state_str[prev_state], - ospf6_neighbor_state_str[next_state], - ospf6_neighbor_event_string(event)); + zlog_debug( + "Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)", + on->name, &on->router_id, + ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); } /* Optionally notify about adjacency changes */ @@ -214,10 +216,13 @@ OSPF6_LOG_ADJACENCY_DETAIL) || (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state))) - zlog_notice("AdjChg: Nbr %s: %s -> %s (%s)", on->name, - ospf6_neighbor_state_str[prev_state], - ospf6_neighbor_state_str[next_state], - ospf6_neighbor_event_string(event)); + zlog_notice( + "AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)", + &on->router_id, + vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id), + on->name, ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) { diff -Nru frr-8.4.2/ospfclient/ospf_apiclient.c frr-8.4.4/ospfclient/ospf_apiclient.c --- frr-8.4.2/ospfclient/ospf_apiclient.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfclient/ospf_apiclient.c 2023-06-16 04:41:18.000000000 +0000 @@ -54,10 +54,6 @@ #include "ospf_apiclient.h" -/* *sigh* ... can't find a better way to hammer this into automake */ -#include "ospfd/ospf_dump_api.c" -#include "ospfd/ospf_api.c" - XREF_SETUP(); DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient"); diff -Nru frr-8.4.2/ospfclient/ospfclient.py frr-8.4.4/ospfclient/ospfclient.py --- frr-8.4.2/ospfclient/ospfclient.py 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfclient/ospfclient.py 2023-06-16 04:41:18.000000000 +0000 @@ -255,6 +255,16 @@ return names.get(state, str(state)) +class WithNothing: + "An object that does nothing when used with `with` statement." + + async def __aenter__(self): + return + + async def __aexit__(self, *args, **kwargs): + return + + # -------------- # Client Classes # -------------- @@ -560,15 +570,17 @@ Args: server: hostname or IP address of server default is "localhost" + wait_ready: if True then wait for OSPF to signal ready, in newer versions + FRR ospfd is always ready so this overhead can be skipped. + default is False. Raises: Will raise exceptions for failures with various `socket` modules functions such as `socket.socket`, `socket.setsockopt`, `socket.bind`. """ - def __init__(self, server="localhost"): + def __init__(self, server="localhost", wait_ready=False): handlers = { - MSG_READY_NOTIFY: self._ready_msg, MSG_LSA_UPDATE_NOTIFY: self._lsa_change_msg, MSG_LSA_DELETE_NOTIFY: self._lsa_change_msg, MSG_NEW_IF: self._if_msg, @@ -578,9 +590,13 @@ MSG_REACHABLE_CHANGE: self._reachable_msg, MSG_ROUTER_ID_CHANGE: self._router_id_msg, } + if wait_ready: + handlers[MSG_READY_NOTIFY] = self._ready_msg + super().__init__(server, handlers) - self.ready_lock = Lock() + self.wait_ready = wait_ready + self.ready_lock = Lock() if wait_ready else WithNothing() self.ready_cond = { LSA_TYPE_OPAQUE_LINK: {}, LSA_TYPE_OPAQUE_AREA: {}, @@ -617,13 +633,9 @@ mp = struct.pack(msg_fmt[mt], lsa_type, otype) await self.msg_send_raises(mt, mp) - async def _assure_opaque_ready(self, lsa_type, otype): - async with self.ready_lock: - if self.ready_cond[lsa_type].get(otype) is True: - return - - await self._register_opaque_data(lsa_type, otype) - await self.wait_opaque_ready(lsa_type, otype) + # If we are not waiting, mark ready for register check + if not self.wait_ready: + self.ready_cond[lsa_type][otype] = True async def _handle_msg_loop(self): try: @@ -656,6 +668,8 @@ return lsa async def _ready_msg(self, mt, msg, extra, lsa_type, otype, addr): + assert self.wait_ready + if lsa_type == LSA_TYPE_OPAQUE_LINK: e = "ifaddr {}".format(ip(addr)) elif lsa_type == LSA_TYPE_OPAQUE_AREA: @@ -825,6 +839,7 @@ Raises: See `msg_send_raises` """ + assert self.ready_cond.get(lsa_type, {}).get(otype) is True, "Not Registered!" if lsa_type == LSA_TYPE_OPAQUE_LINK: ifaddr, aid = int(addr), 0 @@ -842,7 +857,6 @@ *OspfOpaqueClient._opaque_args(lsa_type, otype, oid, data), ) msg += data - await self._assure_opaque_ready(lsa_type, otype) await self.msg_send_raises(mt, msg) async def delete_opaque_data(self, addr, lsa_type, otype, oid, flags=0): @@ -854,21 +868,31 @@ Args: addr: depends on lsa_type, LINK => ifaddr, AREA => area ID, AS => ignored lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS} - otype: (octet) opaque type. Note: the type will be registered if the user - has not explicity done that yet with `register_opaque_data`. + otype: (octet) opaque type. oid: (3 octets) ID of this opaque data flags: (octet) optional flags (e.g., OSPF_API_DEL_ZERO_LEN_LSA, defaults to no flags) Raises: See `msg_send_raises` """ - if (lsa_type, otype) in self.opaque_change_cb: - del self.opaque_change_cb[(lsa_type, otype)] + assert self.ready_cond.get(lsa_type, {}).get(otype) is True, "Not Registered!" mt = MSG_DELETE_REQUEST - await self._assure_opaque_ready(lsa_type, otype) mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, flags, oid) await self.msg_send_raises(mt, mp) + async def is_registered(self, lsa_type, otype): + """Determine if an (lsa_type, otype) tuple has been registered with FRR + + This determines if the type has been registered, but not necessarily if it is + ready, if that is required use the `wait_opaque_ready` metheod. + + Args: + lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS} + otype: (octet) opaque type. + """ + async with self.ready_lock: + return self.ready_cond.get(lsa_type, {}).get(otype) is not None + async def register_opaque_data(self, lsa_type, otype, callback=None): """Register intent to advertise opaque data. @@ -878,8 +902,7 @@ Args: lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS} - otype: (octet) opaque type. Note: the type will be registered if the user - has not explicity done that yet with `register_opaque_data`. + otype: (octet) opaque type. callback: if given, callback will be called when changes are received for LSA of the given (lsa_type, otype). The callbacks signature is: @@ -895,6 +918,10 @@ Raises: See `msg_send_raises` """ + assert not await self.is_registered( + lsa_type, otype + ), "Registering registered type" + if callback: self.opaque_change_cb[(lsa_type, otype)] = callback elif (lsa_type, otype) in self.opaque_change_cb: @@ -913,6 +940,8 @@ if cond is True: return + assert self.wait_ready + logging.debug( "waiting for ready %s opaque-type %s", lsa_typename(lsa_type), otype ) @@ -933,8 +962,7 @@ Args: lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS} - otype: (octet) opaque type. Note: the type will be registered if the user - has not explicity done that yet with `register_opaque_data`. + otype: (octet) opaque type. callback: if given, callback will be called when changes are received for LSA of the given (lsa_type, otype). The callbacks signature is: @@ -951,17 +979,8 @@ See `msg_send_raises` """ - if callback: - self.opaque_change_cb[(lsa_type, otype)] = callback - elif (lsa_type, otype) in self.opaque_change_cb: - logging.warning( - "OSPFCLIENT: register: removing callback for %s opaque-type %s", - lsa_typename(lsa_type), - otype, - ) - del self.opaque_change_cb[(lsa_type, otype)] - - return await self._assure_opaque_ready(lsa_type, otype) + await self.register_opaque_data(lsa_type, otype, callback) + await self.wait_opaque_ready(lsa_type, otype) async def unregister_opaque_data(self, lsa_type, otype): """Unregister intent to advertise opaque data. @@ -971,11 +990,13 @@ Args: lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS} - otype: (octet) opaque type. Note: the type will be registered if the user - has not explicity done that yet with `register_opaque_data`. + otype: (octet) opaque type. Raises: See `msg_send_raises` """ + assert await self.is_registered( + lsa_type, otype + ), "Unregistering unregistered type" if (lsa_type, otype) in self.opaque_change_cb: del self.opaque_change_cb[(lsa_type, otype)] @@ -1081,6 +1102,17 @@ # ================ # CLI/Script Usage # ================ +def next_action(action_list=None): + "Get next action from list or STDIN" + if action_list: + for action in action_list: + yield action + else: + while True: + action = input("") + if not action: + break + yield action.strip() async def async_main(args): @@ -1099,50 +1131,53 @@ await c.req_ism_states() await c.req_nsm_states() - if args.actions: - for action in args.actions: - _s = action.split(",") - what = _s.pop(False) - if what.casefold() == "wait": - stime = int(_s.pop(False)) - logging.info("waiting %s seconds", stime) - await asyncio.sleep(stime) - logging.info("wait complete: %s seconds", stime) - continue - ltype = int(_s.pop(False)) - if ltype == 11: - addr = ip(0) - else: - aval = _s.pop(False) - try: - addr = ip(int(aval)) - except ValueError: - addr = ip(aval) - oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))] - if what.casefold() == "add": + for action in next_action(args.actions): + _s = action.split(",") + what = _s.pop(False) + if what.casefold() == "wait": + stime = int(_s.pop(False)) + logging.info("waiting %s seconds", stime) + await asyncio.sleep(stime) + logging.info("wait complete: %s seconds", stime) + continue + ltype = int(_s.pop(False)) + if ltype == 11: + addr = ip(0) + else: + aval = _s.pop(False) + try: + addr = ip(int(aval)) + except ValueError: + addr = ip(aval) + oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))] + + if not await c.is_registered(oargs[1], oargs[2]): + await c.register_opaque_data_wait(oargs[1], oargs[2]) + + if what.casefold() == "add": + try: + b = bytes.fromhex(_s.pop(False)) + except IndexError: + b = b"" + logging.info("opaque data is %s octets", len(b)) + # Needs to be multiple of 4 in length + mod = len(b) % 4 + if mod: + b += b"\x00" * (4 - mod) + logging.info("opaque padding to %s octets", len(b)) + + await c.add_opaque_data(*oargs, b) + else: + assert what.casefold().startswith("del") + f = 0 + if len(_s) >= 1: try: - b = bytes.fromhex(_s.pop(False)) + f = int(_s.pop(False)) except IndexError: - b = b"" - logging.info("opaque data is %s octets", len(b)) - # Needs to be multiple of 4 in length - mod = len(b) % 4 - if mod: - b += b"\x00" * (4 - mod) - logging.info("opaque padding to %s octets", len(b)) - - await c.add_opaque_data(*oargs, b) - else: - assert what.casefold().startswith("del") - f = 0 - if len(_s) >= 1: - try: - f = int(_s.pop(False)) - except IndexError: - f = 0 - await c.delete_opaque_data(*oargs, f) - if args.exit: - return 0 + f = 0 + await c.delete_opaque_data(*oargs, f) + if not args.actions or args.exit: + return 0 except Exception as error: logging.error("async_main: unexpected error: %s", error, exc_info=True) return 2 @@ -1158,19 +1193,23 @@ def main(*args): ap = argparse.ArgumentParser(args) + ap.add_argument("--logtag", default="CLIENT", help="tag to identify log messages") ap.add_argument("--exit", action="store_true", help="Exit after commands") ap.add_argument("--server", default="localhost", help="OSPF API server") ap.add_argument("-v", "--verbose", action="store_true", help="be verbose") ap.add_argument( "actions", nargs="*", - help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]", + help="WAIT,SEC|(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]", ) args = ap.parse_args() level = logging.DEBUG if args.verbose else logging.INFO logging.basicConfig( - level=level, format="%(asctime)s %(levelname)s: CLIENT: %(name)s %(message)s" + level=level, + format="%(asctime)s %(levelname)s: {}: %(name)s %(message)s".format( + args.logtag + ), ) logging.info("ospfclient: starting") diff -Nru frr-8.4.2/ospfclient/subdir.am frr-8.4.4/ospfclient/subdir.am --- frr-8.4.2/ospfclient/subdir.am 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfclient/subdir.am 2023-06-16 04:41:18.000000000 +0000 @@ -27,6 +27,7 @@ ospfclient_ospfclient_LDADD = \ ospfclient/libfrrospfapiclient.la \ + ospfd/libfrrospfclient.a \ $(LIBCAP) \ # end diff -Nru frr-8.4.2/ospfd/ospf_apiserver.c frr-8.4.4/ospfd/ospf_apiserver.c --- frr-8.4.2/ospfd/ospf_apiserver.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_apiserver.c 2023-06-16 04:41:18.000000000 +0000 @@ -56,10 +56,14 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_errors.h" +#include "ospfd/ospf_memory.h" #include "ospfd/ospf_api.h" #include "ospfd/ospf_apiserver.h" +DEFINE_MTYPE_STATIC(OSPFD, APISERVER, "API Server"); +DEFINE_MTYPE_STATIC(OSPFD, APISERVER_MSGFILTER, "API Server Message Filter"); + /* This is an implementation of an API to the OSPF daemon that allows * external applications to access the OSPF daemon through socket * connections. The application can use this API to inject its own @@ -177,9 +181,14 @@ * Free all client instances. ospf_apiserver_free removes the node * from the list, so we examine the head of the list anew each time. */ - while (apiserver_list - && (apiserv = listgetdata(listhead(apiserver_list))) != NULL) + if (!apiserver_list) + return; + + while (listcount(apiserver_list)) { + apiserv = listgetdata(listhead(apiserver_list)); + ospf_apiserver_free(apiserv); + } /* Free client list itself */ if (apiserver_list) @@ -245,9 +254,9 @@ struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async) { struct ospf_apiserver *new = - XMALLOC(MTYPE_OSPF_APISERVER, sizeof(struct ospf_apiserver)); + XMALLOC(MTYPE_APISERVER, sizeof(struct ospf_apiserver)); - new->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, + new->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER, sizeof(struct lsa_filter_type)); new->fd_sync = fd_sync; @@ -334,6 +343,7 @@ ospf_apiserver_unregister_opaque_type( apiserv, regtype->lsa_type, regtype->opaque_type); } + list_delete(&apiserv->opaque_types); /* Close connections to OSPFd. */ if (apiserv->fd_sync > 0) { @@ -355,12 +365,14 @@ /* Remove from the list of active clients. */ listnode_delete(apiserver_list, apiserv); + XFREE(MTYPE_APISERVER_MSGFILTER, apiserv->filter); + if (IS_DEBUG_OSPF_EVENT) zlog_debug("API: Delete apiserv(%p), total#(%d)", (void *)apiserv, apiserver_list->count); /* And free instance. */ - XFREE(MTYPE_OSPF_APISERVER, apiserv); + XFREE(MTYPE_APISERVER, apiserv); } void ospf_apiserver_read(struct thread *thread) @@ -862,8 +874,8 @@ connection shuts down, we can flush all LSAs of this opaque type. */ - regtype = XCALLOC(MTYPE_OSPF_APISERVER, - sizeof(struct registered_opaque_type)); + regtype = + XCALLOC(MTYPE_APISERVER, sizeof(struct registered_opaque_type)); regtype->lsa_type = lsa_type; regtype->opaque_type = opaque_type; @@ -900,6 +912,7 @@ /* Remove from list of registered opaque types */ listnode_delete(apiserv->opaque_types, regtype); + XFREE(MTYPE_APISERVER, regtype); if (IS_DEBUG_OSPF_EVENT) zlog_debug( "API: Del LSA-type(%d)/Opaque-type(%d) from apiserv(%p), total#(%d)", @@ -1155,12 +1168,12 @@ seqnum = msg_get_seq(msg); /* Free existing filter in apiserv. */ - XFREE(MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter); + XFREE(MTYPE_APISERVER_MSGFILTER, apiserv->filter); /* Alloc new space for filter. */ size = ntohs(msg->hdr.msglen); if (size < OSPF_MAX_LSA_SIZE) { - apiserv->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, size); + apiserv->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER, size); /* copy it over. */ memcpy(apiserv->filter, &rmsg->filter, size); @@ -1365,8 +1378,7 @@ goto out; /* send all adds based on current reachable routers */ - a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, - sizeof(struct in_addr) * rt->count); + a = abuf = XCALLOC(MTYPE_APISERVER, sizeof(struct in_addr) * rt->count); for (struct route_node *rn = route_top(rt); rn; rn = route_next(rn)) if (listhead((struct list *)rn->info)) *a++ = rn->p.u.prefix4; @@ -1385,7 +1397,7 @@ rc = ospf_apiserver_send_msg(apiserv, amsg); msg_free(amsg); } - XFREE(MTYPE_OSPF_APISERVER, abuf); + XFREE(MTYPE_APISERVER, abuf); out: /* Send a reply back to client with return code */ @@ -1767,6 +1779,12 @@ * session. Dump it, but increment past it's seqnum. */ assert(!ospf_opaque_is_owned(old)); + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug( + "LSA[Type%d:%pI4]: OSPF API Server Originate LSA Old Seq: 0x%x Age: %d", + old->data->type, &old->data->id, + ntohl(old->data->ls_seqnum), + ntohl(old->data->ls_age)); if (IS_LSA_MAX_SEQ(old)) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, "%s: old LSA at maxseq", __func__); @@ -1775,6 +1793,11 @@ lsa->data->ls_seqnum = lsa_seqnum_increment(old); ospf_discard_from_db(ospf, old->lsdb, old); } + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug( + "LSA[Type%d:%pI4]: OSPF API Server Originate LSA New Seq: 0x%x Age: %d", + lsa->data->type, &lsa->data->id, + ntohl(lsa->data->ls_seqnum), ntohl(lsa->data->ls_age)); /* Install this LSA into LSDB. */ if (ospf_lsa_install(ospf, lsa->oi, lsa) == NULL) { @@ -1849,6 +1872,11 @@ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); assert(ospf); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%pI4]: OSPF API Server LSA Refresher", + lsa->data->type, &lsa->data->id); + } + apiserv = lookup_apiserver_by_lsa(lsa); if (!apiserv) { zlog_warn("%s: LSA[%s]: No apiserver?", __func__, @@ -1858,14 +1886,14 @@ goto out; } - if (IS_LSA_MAXAGE(lsa)) { - ospf_opaque_lsa_flush_schedule(lsa); - goto out; - } - /* Check if updated version of LSA instance has already prepared. */ new = ospf_lsdb_lookup(&apiserv->reserve, lsa); if (!new) { + if (IS_LSA_MAXAGE(lsa)) { + ospf_opaque_lsa_flush_schedule(lsa); + goto out; + } + /* This is a periodic refresh, driven by core OSPF mechanism. */ new = ospf_apiserver_opaque_lsa_new(lsa->area, lsa->oi, lsa->data); @@ -2590,9 +2618,12 @@ return 1; else if (!nrn) return -1; - else if (orn->p.u.prefix4.s_addr < nrn->p.u.prefix4.s_addr) + + uint32_t opn = ntohl(orn->p.u.prefix4.s_addr); + uint32_t npn = ntohl(nrn->p.u.prefix4.s_addr); + if (opn < npn) return -1; - else if (orn->p.u.prefix4.s_addr > nrn->p.u.prefix4.s_addr) + else if (opn > npn) return 1; else return 0; @@ -2616,9 +2647,9 @@ return; } if (nrt && nrt->count) - a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * nrt->count); + a = abuf = XCALLOC(MTYPE_APISERVER, insz * nrt->count); if (ort && ort->count) - d = dbuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * ort->count); + d = dbuf = XCALLOC(MTYPE_APISERVER, insz * ort->count); /* walk both tables */ orn = ort ? route_top(ort) : NULL; @@ -2683,9 +2714,9 @@ msg_free(msg); } if (abuf) - XFREE(MTYPE_OSPF_APISERVER, abuf); + XFREE(MTYPE_APISERVER, abuf); if (dbuf) - XFREE(MTYPE_OSPF_APISERVER, dbuf); + XFREE(MTYPE_APISERVER, dbuf); } diff -Nru frr-8.4.2/ospfd/ospf_apiserver.h frr-8.4.4/ospfd/ospf_apiserver.h --- frr-8.4.2/ospfd/ospf_apiserver.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_apiserver.h 2023-06-16 04:41:18.000000000 +0000 @@ -26,10 +26,6 @@ #include "ospf_api.h" #include "ospf_lsdb.h" -/* MTYPE definition is not reflected to "memory.h". */ -#define MTYPE_OSPF_APISERVER MTYPE_TMP -#define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP - /* List of opaque types that application registered */ struct registered_opaque_type { uint8_t lsa_type; diff -Nru frr-8.4.2/ospfd/ospf_interface.c frr-8.4.4/ospfd/ospf_interface.c --- frr-8.4.2/ospfd/ospf_interface.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_interface.c 2023-06-16 04:41:18.000000000 +0000 @@ -115,6 +115,9 @@ cost = 1; else if (cost > 65535) cost = 65535; + + if (if_is_loopback(oi->ifp)) + cost = 0; } return cost; @@ -991,7 +994,6 @@ if_delete(&ifp); if (!vrf_is_enabled(vrf)) vrf_delete(vrf); - vlink_count--; } /* for a defined area, count the number of configured vl @@ -1342,18 +1344,28 @@ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) zlog_debug( - "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u", + "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u status 0x%x", ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu, ifp->speed); + ifp->metric, ifp->mtu, ifp->speed, ifp->status); assert(ifp->info); oii = ifp->info; oii->curr_mtu = ifp->mtu; - if (IF_DEF_PARAMS(ifp) - && !OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) { + /* Change ospf type param based on following + * condition: + * ospf type params is not set (first creation), + * OR ospf param type is changed based on + * link event, currently only handle for + * loopback interface type, for other ospf interface, + * type can be set from user config which needs to be + * preserved. + */ + if (IF_DEF_PARAMS(ifp) && + (!OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type) || + if_is_loopback(ifp))) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), type); IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); } diff -Nru frr-8.4.2/ospfd/ospf_lsa.c frr-8.4.4/ospfd/ospf_lsa.c --- frr-8.4.2/ospfd/ospf_lsa.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_lsa.c 2023-06-16 04:41:18.000000000 +0000 @@ -603,7 +603,8 @@ mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; - return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); + return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, + oi->output_cost); } /* Describe Virtual Link. */ @@ -1281,7 +1282,7 @@ struct in_addr old_id) { struct ospf_lsa *lsa = NULL; - struct ospf_lsa *new = NULL; + struct ospf_lsa *summary_lsa = NULL; struct summary_lsa *sl = NULL; struct ospf_area *old_area = NULL; struct prefix_ipv4 old_prefix; @@ -1318,19 +1319,19 @@ if (type == OSPF_SUMMARY_LSA) { /*Refresh the LSA with new LSA*/ - ospf_summary_lsa_refresh(ospf, lsa); + summary_lsa = ospf_summary_lsa_refresh(ospf, lsa); - new = ospf_summary_lsa_prepare_and_flood( - &old_prefix, old_metric, old_area, old_id); + ospf_summary_lsa_prepare_and_flood(&old_prefix, old_metric, + old_area, old_id); } else { /*Refresh the LSA with new LSA*/ - ospf_summary_asbr_lsa_refresh(ospf, lsa); + summary_lsa = ospf_summary_asbr_lsa_refresh(ospf, lsa); - new = ospf_asbr_summary_lsa_prepare_and_flood( - &old_prefix, old_metric, old_area, old_id); + ospf_asbr_summary_lsa_prepare_and_flood(&old_prefix, old_metric, + old_area, old_id); } - return new; + return summary_lsa; } /* Originate Summary-LSA. */ @@ -1999,7 +2000,7 @@ struct ospf_lsa *type7, struct ospf_lsa *type5) { - struct ospf_lsa *new; + struct ospf_lsa *new, *translated_lsa; struct as_external_lsa *extnew; if (ospf->gr_info.restart_in_progress) { @@ -2013,7 +2014,8 @@ * the OSPF_LSA_LOCAL_XLT flag, must originate by hand */ - if ((new = ospf_lsa_translated_nssa_new(ospf, type7)) == NULL) { + if ((translated_lsa = ospf_lsa_translated_nssa_new(ospf, type7)) == + NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug( "%s: Could not translate Type-7, Id %pI4, to Type-5", @@ -2021,16 +2023,17 @@ return NULL; } - extnew = (struct as_external_lsa *)new->data; + extnew = (struct as_external_lsa *)translated_lsa->data; /* Update LSA sequence number from translated Type-5 LSA */ if (type5) - new->data->ls_seqnum = lsa_seqnum_increment(type5); + translated_lsa->data->ls_seqnum = lsa_seqnum_increment(type5); - if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) { + if ((new = ospf_lsa_install(ospf, NULL, translated_lsa)) == NULL) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, "%s: Could not install LSA id %pI4", __func__, &type7->data->id); + ospf_lsa_free(translated_lsa); return NULL; } @@ -2053,7 +2056,7 @@ struct ospf_lsa *type7, struct ospf_lsa *type5) { - struct ospf_lsa *new = NULL; + struct ospf_lsa *new = NULL, *translated_lsa = NULL; struct as_external_lsa *extold = NULL; uint32_t ls_seqnum = 0; @@ -2129,7 +2132,8 @@ ospf_ls_retransmit_delete_nbr_as(ospf, type5); /* create new translated LSA */ - if ((new = ospf_lsa_translated_nssa_new(ospf, type7)) == NULL) { + if ((translated_lsa = ospf_lsa_translated_nssa_new(ospf, type7)) == + NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug( "%s: Could not translate Type-7 for %pI4 to Type-5", @@ -2139,13 +2143,14 @@ if (type7->area->suppress_fa == 1) { if (extold->e[0].fwd_addr.s_addr == 0) - new->data->ls_seqnum = htonl(ls_seqnum + 1); + translated_lsa->data->ls_seqnum = htonl(ls_seqnum + 1); } - if (!(new = ospf_lsa_install(ospf, NULL, new))) { + if (!(new = ospf_lsa_install(ospf, NULL, translated_lsa))) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, "%s: Could not install translated LSA, Id %pI4", __func__, &type7->data->id); + ospf_lsa_free(translated_lsa); return NULL; } diff -Nru frr-8.4.2/ospfd/ospf_nsm.c frr-8.4.4/ospfd/ospf_nsm.c --- frr-8.4.2/ospfd/ospf_nsm.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_nsm.c 2023-06-16 04:41:18.000000000 +0000 @@ -644,12 +644,13 @@ if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) || (next_state == NSM_Full) || (next_state < nbr->state))) - zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)", - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi), - lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), - lookup_msg(ospf_nsm_state_msg, next_state, NULL), - ospf_nsm_event_str[event]); + zlog_notice( + "AdjChg: Nbr %pI4, NbrIP %pI4 (%s) on %s: %s -> %s (%s)", + &nbr->router_id, &nbr->src, + ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi), + lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), + lookup_msg(ospf_nsm_state_msg, next_state, NULL), + ospf_nsm_event_str[event]); /* Advance in NSM */ if (next_state > nbr->state) diff -Nru frr-8.4.2/ospfd/ospf_opaque.c frr-8.4.4/ospfd/ospf_opaque.c --- frr-8.4.2/ospfd/ospf_opaque.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_opaque.c 2023-06-16 04:41:18.000000000 +0000 @@ -34,6 +34,7 @@ #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ +#include "printfrr.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -131,6 +132,10 @@ ospf_ext_finish(); +#ifdef SUPPORT_OSPF_API + ospf_apiserver_term(); +#endif + ospf_sr_finish(); } @@ -1162,11 +1167,13 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, json_object *json) { + char buf[128], *bp; struct lsa_header *lsah = lsa->data; uint32_t lsid = ntohl(lsah->id.s_addr); uint8_t opaque_type = GET_OPAQUE_TYPE(lsid); uint32_t opaque_id = GET_OPAQUE_ID(lsid); struct ospf_opaque_functab *functab; + int len, lenValid; /* Switch output functionality by vty address. */ if (vty != NULL) { @@ -1185,11 +1192,19 @@ json, "opaqueType", ospf_opaque_type_name(opaque_type)); json_object_int_add(json, "opaqueId", opaque_id); - json_object_int_add(json, "opaqueDataLength", - ntohs(lsah->length) - - OSPF_LSA_HEADER_SIZE); + len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + json_object_int_add(json, "opaqueDataLength", len); + lenValid = VALID_OPAQUE_INFO_LEN(lsah); json_object_boolean_add(json, "opaqueDataLengthValid", - VALID_OPAQUE_INFO_LEN(lsah)); + lenValid); + if (lenValid) { + bp = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), + "%*pHXn", (int)len, + (lsah + 1)); + json_object_string_add(json, "opaqueData", buf); + if (bp != buf) + XFREE(MTYPE_TMP, bp); + } } } else { zlog_debug(" Opaque-Type %u (%s)", opaque_type, @@ -2112,14 +2127,21 @@ lsa->data->type, &lsa->data->id); /* - * Since these LSA entries are not yet installed into corresponding - * LSDB, just flush them without calling ospf_ls_maxage() afterward. + * Install the stale LSA into the Link State Database, add it to the + * MaxAge list, and flush it from the OSPF routing domain. For other + * LSA types, the installation is done in the refresh function. It is + * done inline here since the opaque refresh function is dynamically + * registered when opaque LSAs are originated (which is not the case + * for stale LSAs). */ lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); + ospf_lsa_install( + top, (lsa->data->type == OSPF_OPAQUE_LINK_LSA) ? nbr->oi : NULL, + lsa); + ospf_lsa_maxage(top, lsa); + switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: - ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa); - break; case OSPF_OPAQUE_AREA_LSA: ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa); break; @@ -2131,7 +2153,6 @@ __func__, lsa->data->type); return; } - ospf_lsa_discard(lsa); /* List "lsas" will be deleted by caller. */ } /*------------------------------------------------------------------------* diff -Nru frr-8.4.2/ospfd/ospf_packet.c frr-8.4.4/ospfd/ospf_packet.c --- frr-8.4.2/ospfd/ospf_packet.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_packet.c 2023-06-16 04:41:18.000000000 +0000 @@ -322,8 +322,10 @@ ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt), ospfh->u.crypt.key_id); if (ck == NULL) { - flog_warn(EC_OSPF_MD5, "interface %s: ospf_check_md5 no key %d", - IF_NAME(oi), ospfh->u.crypt.key_id); + flog_warn( + EC_OSPF_MD5, + "interface %s: ospf_check_md5 no key %d, Router-ID: %pI4", + IF_NAME(oi), ospfh->u.crypt.key_id, &ospfh->router_id); return 0; } @@ -334,9 +336,9 @@ && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) { flog_warn( EC_OSPF_MD5, - "interface %s: ospf_check_md5 bad sequence %d (expect %d)", + "interface %s: ospf_check_md5 bad sequence %d (expect %d), Router-ID: %pI4", IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum), - ntohl(nbr->crypt_seqnum)); + ntohl(nbr->crypt_seqnum), &ospfh->router_id); return 0; } @@ -359,9 +361,10 @@ /* compare the two */ if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) { - flog_warn(EC_OSPF_MD5, - "interface %s: ospf_check_md5 checksum mismatch", - IF_NAME(oi)); + flog_warn( + EC_OSPF_MD5, + "interface %s: ospf_check_md5 checksum mismatch, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); return 0; } @@ -440,10 +443,11 @@ if (stream_get_endp(op->s) != op->length) /* XXX size_t */ - flog_warn(EC_OSPF_MD5, - "%s: length mismatch stream %lu ospf_packet %u", - __func__, (unsigned long)stream_get_endp(op->s), - op->length); + flog_warn( + EC_OSPF_MD5, + "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4", + __func__, (unsigned long)stream_get_endp(op->s), + op->length, &ospfh->router_id); return OSPF_AUTH_MD5_SIZE; } @@ -910,11 +914,11 @@ /* Compare Router Dead Interval. */ if (OSPF_IF_PARAM(oi, v_wait) != ntohl(hello->dead_interval)) { - flog_warn(EC_OSPF_PACKET, - "Packet %pI4 [Hello:RECV]: RouterDeadInterval mismatch (expected %u, but received %u).", - &ospfh->router_id, - OSPF_IF_PARAM(oi, v_wait), - ntohl(hello->dead_interval)); + flog_warn( + EC_OSPF_PACKET, + "Packet %pI4 [Hello:RECV]: RouterDeadInterval mismatch on %s (expected %u, but received %u).", + &ospfh->router_id, IF_NAME(oi), + OSPF_IF_PARAM(oi, v_wait), ntohl(hello->dead_interval)); return; } @@ -924,8 +928,8 @@ != ntohs(hello->hello_interval)) { flog_warn( EC_OSPF_PACKET, - "Packet %pI4 [Hello:RECV]: HelloInterval mismatch (expected %u, but received %u).", - &ospfh->router_id, + "Packet %pI4 [Hello:RECV]: HelloInterval mismatch on %s (expected %u, but received %u).", + &ospfh->router_id, IF_NAME(oi), OSPF_IF_PARAM(oi, v_hello), ntohs(hello->hello_interval)); return; @@ -933,8 +937,8 @@ } if (IS_DEBUG_OSPF_EVENT) - zlog_debug("Packet %pI4 [Hello:RECV]: Options %s vrf %s", - &ospfh->router_id, + zlog_debug("Packet %pI4 [Hello:RECV]: Options on %s %s vrf %s", + &ospfh->router_id, IF_NAME(oi), ospf_options_dump(hello->options), ospf_vrf_id_to_name(oi->ospf->vrf_id)); @@ -948,8 +952,8 @@ * relationship. */ flog_warn(EC_OSPF_PACKET, - "Packet %pI4 [Hello:RECV]: T-bit on, drop it.", - &ospfh->router_id); + "Packet %pI4 [Hello:RECV]: T-bit ON on %s, drop it.", + &ospfh->router_id, IF_NAME(oi)); return; } #endif /* REJECT_IF_TBIT_ON */ @@ -961,8 +965,8 @@ * the bit should be set in DD packet only. */ flog_warn(EC_OSPF_PACKET, - "Packet %pI4 [Hello:RECV]: O-bit abuse?", - &ospfh->router_id); + "Packet %pI4 [Hello:RECV]: O-bit abuse? on %s", + &ospfh->router_id, IF_NAME(oi)); #ifdef STRICT_OBIT_USAGE_CHECK return; /* Reject this packet. */ #else /* STRICT_OBIT_USAGE_CHECK */ @@ -2032,7 +2036,7 @@ if (current == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[%s]: Previously originated Opaque-LSA,not found in the LSDB.", + "LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key(lsa)); SET_FLAG(lsa->flags, OSPF_LSA_SELF); @@ -2484,10 +2488,11 @@ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) flog_warn( EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Null", + "interface %s: auth-type mismatch, local %s, rcvd Null, Router-ID %pI4", IF_NAME(oi), lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL)); + iface_auth_type, NULL), + &ospfh->router_id); return 0; } if (!ospf_check_sum(ospfh)) { @@ -2506,18 +2511,20 @@ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) flog_warn( EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Simple", + "interface %s: auth-type mismatch, local %s, rcvd Simple, Router-ID %pI4", IF_NAME(oi), lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL)); + iface_auth_type, NULL), + &ospfh->router_id); return 0; } if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) { if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn(EC_OSPF_PACKET, - "interface %s: Simple auth failed", - IF_NAME(oi)); + flog_warn( + EC_OSPF_PACKET, + "interface %s: Simple auth failed, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); return 0; } if (!ospf_check_sum(ospfh)) { @@ -2536,18 +2543,19 @@ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) flog_warn( EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Cryptographic", + "interface %s: auth-type mismatch, local %s, rcvd Cryptographic, Router-ID %pI4", IF_NAME(oi), lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL)); + iface_auth_type, NULL), + &ospfh->router_id); return 0; } if (ospfh->checksum) { if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) flog_warn( EC_OSPF_PACKET, - "interface %s: OSPF header checksum is not 0", - IF_NAME(oi)); + "interface %s: OSPF header checksum is not 0, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); return 0; } /* only MD5 crypto method can pass ospf_packet_examin() */ @@ -2560,9 +2568,10 @@ bug? */ !ospf_check_md5_digest(oi, ospfh)) { if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn(EC_OSPF_MD5, - "interface %s: MD5 auth failed", - IF_NAME(oi)); + flog_warn( + EC_OSPF_MD5, + "interface %s: MD5 auth failed, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); return 0; } return 1; @@ -2570,8 +2579,8 @@ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) flog_warn( EC_OSPF_PACKET, - "interface %s: invalid packet auth-type (%02x)", - IF_NAME(oi), pkt_auth_type); + "interface %s: invalid packet auth-type (%02x), Router-ID %pI4", + IF_NAME(oi), pkt_auth_type, &ospfh->router_id); return 0; } } diff -Nru frr-8.4.2/ospfd/ospf_route.c frr-8.4.4/ospfd/ospf_route.c --- frr-8.4.2/ospfd/ospf_route.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_route.c 2023-06-16 04:41:18.000000000 +0000 @@ -363,45 +363,50 @@ /* RFC2328 16.1. (4). For "router". */ void ospf_intra_add_router(struct route_table *rt, struct vertex *v, - struct ospf_area *area, bool add_all) + struct ospf_area *area, bool add_only) { struct route_node *rn; struct ospf_route * or ; struct prefix_ipv4 p; struct router_lsa *lsa; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: Start", __func__); - + if (IS_DEBUG_OSPF_EVENT) { + if (!add_only) + zlog_debug("%s: Start", __func__); + else + zlog_debug("%s: REACHRUN: Start", __func__); + } lsa = (struct router_lsa *)v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: LS ID: %pI4", __func__, &lsa->header.id); - if (!OSPF_IS_AREA_BACKBONE(area)) - ospf_vl_up_check(area, lsa->header.id, v); - - if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT)) - area->shortcut_capability = 0; - - /* If the newly added vertex is an area border router or AS boundary - router, a routing table entry is added whose destination type is - "router". */ - if (!add_all && !IS_ROUTER_LSA_BORDER(lsa) && - !IS_ROUTER_LSA_EXTERNAL(lsa)) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "%s: this router is neither ASBR nor ABR, skipping it", - __func__); - return; + if (!add_only) { + if (!OSPF_IS_AREA_BACKBONE(area)) + ospf_vl_up_check(area, lsa->header.id, v); + + if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT)) + area->shortcut_capability = 0; + + /* If the newly added vertex is an area border router or AS + boundary router, a routing table entry is added whose + destination type is "router". */ + if (!IS_ROUTER_LSA_BORDER(lsa) && + !IS_ROUTER_LSA_EXTERNAL(lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "%s: this router is neither ASBR nor ABR, skipping it", + __func__); + return; + } + + /* Update ABR and ASBR count in this area. */ + if (IS_ROUTER_LSA_BORDER(lsa)) + area->abr_count++; + if (IS_ROUTER_LSA_EXTERNAL(lsa)) + area->asbr_count++; } - /* Update ABR and ASBR count in this area. */ - if (IS_ROUTER_LSA_BORDER(lsa)) - area->abr_count++; - if (IS_ROUTER_LSA_EXTERNAL(lsa)) - area->asbr_count++; - /* The Options field found in the associated router-LSA is copied into the routing table entry's Optional capabilities field. Call the newly added vertex Router X. */ @@ -448,8 +453,12 @@ listnode_add(rn->info, or); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: Stop", __func__); + if (IS_DEBUG_OSPF_EVENT) { + if (!add_only) + zlog_debug("%s: Stop", __func__); + else + zlog_debug("%s: REACHRUN: Stop", __func__); + } } /* RFC2328 16.1. (4). For transit network. */ diff -Nru frr-8.4.2/ospfd/ospf_snmp.c frr-8.4.4/ospfd/ospf_snmp.c --- frr-8.4.2/ospfd/ospf_snmp.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_snmp.c 2023-06-16 04:41:18.000000000 +0000 @@ -50,6 +50,8 @@ #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" +DEFINE_MTYPE_STATIC(OSPFD, SNMP, "OSPF SNMP"); + /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 @@ -1321,12 +1323,12 @@ static struct ospf_snmp_if *ospf_snmp_if_new(void) { - return XCALLOC(MTYPE_TMP, sizeof(struct ospf_snmp_if)); + return XCALLOC(MTYPE_SNMP, sizeof(struct ospf_snmp_if)); } static void ospf_snmp_if_free(struct ospf_snmp_if *osif) { - XFREE(MTYPE_TMP, osif); + XFREE(MTYPE_SNMP, osif); } static int ospf_snmp_if_delete(struct interface *ifp) diff -Nru frr-8.4.2/ospfd/ospf_spf.c frr-8.4.4/ospfd/ospf_spf.c --- frr-8.4.2/ospfd/ospf_spf.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_spf.c 2023-06-16 04:41:18.000000000 +0000 @@ -1748,7 +1748,8 @@ if (v->type != OSPF_VERTEX_ROUTER) ospf_intra_add_transit(new_table, v, area); else { - ospf_intra_add_router(new_rtrs, v, area, false); + if (new_rtrs) + ospf_intra_add_router(new_rtrs, v, area, false); if (all_rtrs) ospf_intra_add_router(all_rtrs, v, area, true); } diff -Nru frr-8.4.2/ospfd/ospf_ti_lfa.c frr-8.4.4/ospfd/ospf_ti_lfa.c --- frr-8.4.2/ospfd/ospf_ti_lfa.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_ti_lfa.c 2023-06-16 04:41:18.000000000 +0000 @@ -252,7 +252,7 @@ struct q_space *q_space, struct ospf_ti_lfa_inner_backup_path_info *inner_backup_path_info) { - struct route_table *new_table, *new_rtrs; + struct route_table *new_table; struct vertex *q_node; struct vertex *start_vertex, *end_vertex; struct vertex_parent *vertex_parent; @@ -315,7 +315,6 @@ start_vertex, end_vertex); new_table = route_table_init(); - new_rtrs = route_table_init(); /* Copy the current state ... */ spf_orig = area->spf; @@ -326,7 +325,7 @@ XCALLOC(MTYPE_OSPF_P_SPACE, sizeof(struct p_spaces_head)); /* dry run true, root node false */ - ospf_spf_calculate(area, start_vertex->lsa_p, new_table, NULL, new_rtrs, + ospf_spf_calculate(area, start_vertex->lsa_p, new_table, NULL, NULL, true, false); q_node = ospf_spf_vertex_find(end_vertex->id, area->spf_vertex_list); @@ -637,7 +636,7 @@ { struct listnode *node; struct vertex *child; - struct route_table *new_table, *new_rtrs; + struct route_table *new_table; struct q_space *q_space, q_space_search; char label_buf[MPLS_LABEL_STRLEN]; char res_buf[PROTECTED_RESOURCE_STRLEN]; @@ -676,15 +675,13 @@ sizeof(struct ospf_ti_lfa_node_info)); new_table = route_table_init(); - /* XXX do these get freed?? */ - new_rtrs = route_table_init(); /* * Generate a new (reversed!) SPF tree for this vertex, * dry run true, root node false */ area->spf_reversed = true; - ospf_spf_calculate(area, dest->lsa_p, new_table, NULL, new_rtrs, true, + ospf_spf_calculate(area, dest->lsa_p, new_table, NULL, NULL, true, false); /* Reset the flag for reverse SPF */ @@ -707,6 +704,11 @@ "%s: NO backup path found for root %pI4 and destination %pI4 for %s, aborting ...", __func__, &p_space->root->id, &q_space->root->id, res_buf); + + XFREE(MTYPE_OSPF_Q_SPACE, q_space->p_node_info); + XFREE(MTYPE_OSPF_Q_SPACE, q_space->q_node_info); + XFREE(MTYPE_OSPF_Q_SPACE, q_space); + return; } @@ -749,11 +751,9 @@ static void ospf_ti_lfa_generate_post_convergence_spf(struct ospf_area *area, struct p_space *p_space) { - struct route_table *new_table, *new_rtrs; + struct route_table *new_table; new_table = route_table_init(); - /* XXX do these get freed?? */ - new_rtrs = route_table_init(); area->spf_protected_resource = p_space->protected_resource; @@ -772,8 +772,8 @@ * endeavour (because LSAs are stored as a 'raw' stream), so we go with * this rather hacky way for now. */ - ospf_spf_calculate(area, area->router_lsa_self, new_table, NULL, - new_rtrs, true, false); + ospf_spf_calculate(area, area->router_lsa_self, new_table, NULL, NULL, + true, false); p_space->pc_spf = area->spf; p_space->pc_vertex_list = area->spf_vertex_list; diff -Nru frr-8.4.2/ospfd/ospf_vty.c frr-8.4.4/ospfd/ospf_vty.c --- frr-8.4.2/ospfd/ospf_vty.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/ospf_vty.c 2023-06-16 04:41:18.000000000 +0000 @@ -3945,16 +3945,15 @@ /* Interface name is specified. */ ifp = if_lookup_by_name(intf_name, ospf->vrf_id); if (ifp == NULL) { - if (use_json) + if (use_json) { json_object_boolean_true_add(json_vrf, "noSuchIface"); - else + json_object_free(json_interface); + } else vty_out(vty, "No such interface name\n"); } else { - if (use_json) { + if (use_json) json_interface_sub = json_object_new_object(); - json_interface = json_object_new_object(); - } show_ip_ospf_interface_sub( vty, ospf, ifp, json_interface_sub, use_json); diff -Nru frr-8.4.2/ospfd/subdir.am frr-8.4.4/ospfd/subdir.am --- frr-8.4.2/ospfd/subdir.am 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/ospfd/subdir.am 2023-06-16 04:41:18.000000000 +0000 @@ -4,6 +4,7 @@ if OSPFD noinst_LIBRARIES += ospfd/libfrrospf.a +noinst_LIBRARIES += ospfd/libfrrospfclient.a sbin_PROGRAMS += ospfd/ospfd vtysh_scan += \ ospfd/ospf_bfd.c \ @@ -24,6 +25,11 @@ man8 += $(MANBUILD)/frr-ospfd.8 endif +ospfd_libfrrospfclient_a_SOURCES = \ + ospfd/ospf_api.c \ + ospfd/ospf_dump_api.c \ + #end + ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_abr.c \ ospfd/ospf_api.c \ @@ -114,7 +120,7 @@ ospfd/ospf_zebra.h \ # end -ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) +ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c diff -Nru frr-8.4.2/pbrd/pbr_vty.c frr-8.4.4/pbrd/pbr_vty.c --- frr-8.4.2/pbrd/pbr_vty.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pbrd/pbr_vty.c 2023-06-16 04:41:18.000000000 +0000 @@ -140,7 +140,7 @@ if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) { + if (pbrms->dst && prefix->family != pbrms->dst->family) { vty_out(vty, "Cannot mismatch families within match src/dst\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -176,7 +176,7 @@ if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (pbrms->src && pbrms->family && prefix->family != pbrms->family) { + if (pbrms->src && prefix->family != pbrms->src->family) { vty_out(vty, "Cannot mismatch families within match src/dst\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -935,12 +935,12 @@ if (detail) vty_out(vty, - " Installed: %u(%d) Tableid: %d\n", + " Installed: %u(%d) Tableid: %u\n", pbrms->nhs_installed, pbr_nht_get_installed(pbrms->nhgrp_name), pbr_nht_get_table(pbrms->nhgrp_name)); else - vty_out(vty, " Installed: %s Tableid: %d\n", + vty_out(vty, " Installed: %s Tableid: %u\n", pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes" : "no", pbr_nht_get_table(pbrms->nhgrp_name)); @@ -950,12 +950,12 @@ pbrms_nexthop_group_write_individual_nexthop(vty, pbrms); if (detail) vty_out(vty, - " Installed: %u(%d) Tableid: %d\n", + " Installed: %u(%d) Tableid: %u\n", pbrms->nhs_installed, pbr_nht_get_installed(pbrms->internal_nhg_name), pbr_nht_get_table(pbrms->internal_nhg_name)); else - vty_out(vty, " Installed: %s Tableid: %d\n", + vty_out(vty, " Installed: %s Tableid: %u\n", pbr_nht_get_installed(pbrms->internal_nhg_name) ? "yes" : "no", diff -Nru frr-8.4.2/pceplib/pcep_utils_counters.h frr-8.4.4/pceplib/pcep_utils_counters.h --- frr-8.4.2/pceplib/pcep_utils_counters.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pceplib/pcep_utils_counters.h 2023-06-16 04:41:18.000000000 +0000 @@ -30,6 +30,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff -Nru frr-8.4.2/pimd/pim_bsm.c frr-8.4.4/pimd/pim_bsm.c --- frr-8.4.2/pimd/pim_bsm.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_bsm.c 2023-06-16 04:41:18.000000000 +0000 @@ -170,7 +170,6 @@ pim_nht_bsr_del(scope->pim, scope->current_bsr); /* Reset scope zone data */ - scope->accept_nofwd_bsm = false; scope->state = ACCEPT_ANY; scope->current_bsr = PIMADDR_ANY; scope->current_bsr_prio = 0; @@ -1378,6 +1377,10 @@ } } + /* BSM packet is seen, so resetting accept_nofwd_bsm to false */ + if (pim->global_scope.accept_nofwd_bsm) + pim->global_scope.accept_nofwd_bsm = false; + if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) { /* Multicast BSMs are only accepted if source interface & IP * match RPF towards the BSR's IP address, or they have diff -Nru frr-8.4.2/pimd/pim_mroute.c frr-8.4.4/pimd/pim_mroute.c --- frr-8.4.2/pimd/pim_mroute.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_mroute.c 2023-06-16 04:41:18.000000000 +0000 @@ -47,6 +47,8 @@ #include "pim_msg.h" static void mroute_read_on(struct pim_instance *pim); +static int pim_upstream_mroute_update(struct channel_oil *c_oil, + const char *name); int pim_mroute_set(struct pim_instance *pim, int enable) { @@ -160,19 +162,36 @@ struct pim_upstream *up; struct pim_rpf *rpg; pim_sgaddr sg; + bool desync = false; - rpg = pim_ifp ? RP(pim_ifp->pim, msg->msg_im_dst) : NULL; + memset(&sg, 0, sizeof(sg)); + sg.src = msg->msg_im_src; + sg.grp = msg->msg_im_dst; + + if (!pim_ifp) { + if (PIM_DEBUG_MROUTE) + zlog_debug( + "%s: PIM not enabled on interface, dropping packet to %pSG", + ifp->name, &sg); + return 0; + } + + rpg = RP(pim_ifp->pim, msg->msg_im_dst); /* * If the incoming interface is unknown OR * the Interface type is SSM we don't need to * do anything here */ - if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) { - if (PIM_DEBUG_MROUTE_DETAIL) - zlog_debug( - "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP", - __func__); - + if (!rpg) { + if (PIM_DEBUG_MROUTE) + zlog_debug("%s: no RPF for packet to %pSG", ifp->name, + &sg); + return 0; + } + if (pim_rpf_addr_is_inaddr_any(rpg)) { + if (PIM_DEBUG_MROUTE) + zlog_debug("%s: null RPF for packet to %pSG", ifp->name, + &sg); return 0; } @@ -181,22 +200,21 @@ * us */ if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) { - if (PIM_DEBUG_MROUTE_DETAIL) + if (PIM_DEBUG_MROUTE) zlog_debug( - "%s: Received incoming packet that doesn't originate on our seg", - __func__); + "%s: incoming packet to %pSG from non-connected source", + ifp->name, &sg); return 0; } - memset(&sg, 0, sizeof(sg)); - sg.src = msg->msg_im_src; - sg.grp = msg->msg_im_dst; - if (!(PIM_I_am_DR(pim_ifp))) { + /* unlike the other debug messages, this one is further in the + * "normal operation" category and thus under _DETAIL + */ if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug( - "%s: Interface is not the DR blackholing incoming traffic for %pSG", - __func__, &sg); + "%s: not DR on interface, not forwarding traffic for %pSG", + ifp->name, &sg); /* * We are not the DR, but we are still receiving packets @@ -217,6 +235,12 @@ up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __func__); + if (up->channel_oil->installed) { + zlog_warn( + "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling", + ifp->name, &sg); + desync = true; + } /* * I moved this debug till after the actual add because @@ -240,6 +264,11 @@ /* if we have receiver, inherit from parent */ pim_upstream_inherited_olist_decide(pim_ifp->pim, up); + /* we just got NOCACHE from the kernel, so... MFC is not in the + * kernel for some reason or another. Try installing again. + */ + if (desync) + pim_upstream_mroute_update(up->channel_oil, __func__); return 0; } diff -Nru frr-8.4.2/pimd/pim_neighbor.c frr-8.4.4/pimd/pim_neighbor.c --- frr-8.4.2/pimd/pim_neighbor.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_neighbor.c 2023-06-16 04:41:18.000000000 +0000 @@ -42,6 +42,7 @@ #include "pim_jp_agg.h" #include "pim_bfd.h" #include "pim_register.h" +#include "pim_oil.h" static void dr_election_by_addr(struct interface *ifp) { @@ -136,9 +137,10 @@ pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); - if (PIM_I_am_DR(pim_ifp)) + if (PIM_I_am_DR(pim_ifp)) { pim_ifp->am_i_dr = true; - else { + pim_clear_nocache_state(pim_ifp); + } else { if (pim_ifp->am_i_dr == true) { pim_reg_del_on_couldreg_fail(ifp); pim_ifp->am_i_dr = false; diff -Nru frr-8.4.2/pimd/pim_oil.c frr-8.4.4/pimd/pim_oil.c --- frr-8.4.2/pimd/pim_oil.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_oil.c 2023-06-16 04:41:18.000000000 +0000 @@ -162,6 +162,31 @@ return c_oil; } + +/* + * Clean up mroute and channel oil created for dropping pkts from directly + * connected source when the interface was non DR. + */ +void pim_clear_nocache_state(struct pim_interface *pim_ifp) +{ + struct channel_oil *c_oil; + + frr_each_safe (rb_pim_oil, &pim_ifp->pim->channel_oil_head, c_oil) { + + if ((!c_oil->up) || + !(PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(c_oil->up->flags))) + continue; + + if (*oil_parent(c_oil) != pim_ifp->mroute_vif_index) + continue; + + THREAD_OFF(c_oil->up->t_ka_timer); + PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(c_oil->up->flags); + PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(c_oil->up->flags); + pim_upstream_del(pim_ifp->pim, c_oil->up, __func__); + } +} + struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil, const char *name) { diff -Nru frr-8.4.2/pimd/pim_oil.h frr-8.4.4/pimd/pim_oil.h --- frr-8.4.2/pimd/pim_oil.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_oil.h 2023-06-16 04:41:18.000000000 +0000 @@ -195,6 +195,7 @@ pim_sgaddr *sg); struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, pim_sgaddr *sg, const char *name); +void pim_clear_nocache_state(struct pim_interface *pim_ifp); struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil, const char *name); diff -Nru frr-8.4.2/pimd/pim_util.c frr-8.4.4/pimd/pim_util.c --- frr-8.4.2/pimd/pim_util.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_util.c 2023-06-16 04:41:18.000000000 +0000 @@ -172,7 +172,7 @@ bool pim_addr_is_multicast(pim_addr addr) { #if PIM_IPV == 4 - if (IN_MULTICAST(addr.s_addr)) + if (IN_MULTICAST(ntohl(addr.s_addr))) return true; #else if (IN6_IS_ADDR_MULTICAST(&addr)) diff -Nru frr-8.4.2/pimd/pim_zebra.c frr-8.4.4/pimd/pim_zebra.c --- frr-8.4.2/pimd/pim_zebra.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/pimd/pim_zebra.c 2023-06-16 04:41:18.000000000 +0000 @@ -68,6 +68,8 @@ { struct interface *ifp; vrf_id_t new_vrf_id; + struct pim_instance *pim; + struct pim_interface *pim_ifp; ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &new_vrf_id); @@ -78,8 +80,18 @@ zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name, vrf_id, new_vrf_id); + pim = pim_get_pim_instance(new_vrf_id); + if_update_to_new_vrf(ifp, new_vrf_id); + pim_ifp = ifp->info; + if (!pim_ifp) + return 0; + + pim_ifp->pim->mcast_if_count--; + pim_ifp->pim = pim; + pim_ifp->pim->mcast_if_count++; + return 0; } diff -Nru frr-8.4.2/redhat/frr.spec.in frr-8.4.4/redhat/frr.spec.in --- frr-8.4.2/redhat/frr.spec.in 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/redhat/frr.spec.in 2023-06-16 04:41:18.000000000 +0000 @@ -793,7 +793,13 @@ %changelog -* Mon Jan 09 2023 Martin Winter - %{version} +* Thu Jun 15 2023 Martin Winter - %{version} + +* Thu Jun 15 2023 Jafar Al-Gharaibeh - 8.4.4 +- This a convenience release/tag for house keeping + +* Wed Mar 15 2023 Jafar Al-Gharaibeh - 8.4.3 +- This a convenience release/tag for house keeping * Mon Jan 09 2023 Jafar Al-Gharaibeh - 8.4.2 - bfdd: fix ipv4 socket source selection diff -Nru frr-8.4.2/tests/bgpd/test_mp_attr.c frr-8.4.4/tests/bgpd/test_mp_attr.c --- frr-8.4.2/tests/bgpd/test_mp_attr.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/bgpd/test_mp_attr.c 2023-06-16 04:41:18.000000000 +0000 @@ -1057,9 +1057,9 @@ if (!parse_ret) { if (type == BGP_ATTR_MP_REACH_NLRI) - nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, 0); + nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, false); else if (type == BGP_ATTR_MP_UNREACH_NLRI) - nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, 1); + nlri_ret = bgp_nlri_parse(peer, &attr, &nlri, true); } handle_result(peer, t, parse_ret, nlri_ret); } diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r1/bgpd.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r1/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r1/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r1/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,12 @@ +router bgp 65001 + no bgp ebgp-requires-policy + bgp confederation identifier 65300 + bgp confederation peers 65002 65003 + neighbor fabric peer-group + neighbor fabric remote-as external + neighbor 192.168.1.2 peer-group fabric + neighbor 192.168.2.2 remote-as external + address-family ipv4 unicast + neighbor fabric activate + exit-address-family +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r1/zebra.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r1/zebra.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r1/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r1/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,7 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.2.1/24 +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r2/bgpd.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r2/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r2/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r2/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,13 @@ +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + bgp confederation identifier 65300 + bgp confederation peers 65001 + neighbor fabric peer-group + neighbor fabric remote-as external + neighbor 192.168.1.1 peer-group fabric + address-family ipv4 unicast + network 172.16.255.254/32 + neighbor fabric activate + exit-address-family +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r2/zebra.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r2/zebra.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r2/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r2/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,4 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r3/bgpd.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r3/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r3/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r3/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,10 @@ +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + bgp confederation identifier 65300 + bgp confederation peers 65001 + neighbor 192.168.2.1 remote-as external + address-family ipv4 unicast + network 172.16.255.254/32 + exit-address-family +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/r3/zebra.conf frr-8.4.4/tests/topotests/bgp_confederation_astype/r3/zebra.conf --- frr-8.4.2/tests/topotests/bgp_confederation_astype/r3/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/r3/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,4 @@ +! +int r3-eth0 + ip address 192.168.2.2/24 +! diff -Nru frr-8.4.2/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py frr-8.4.4/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py --- frr-8.4.2/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2022 by +# Donatas Abraitis +# + +""" +Test if BGP confederation works properly when using +remote-as internal/external. + +Also, check if the same works with peer-groups as well. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_confederation_astype(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp summary json")) + expected = { + "ipv4Unicast": { + "peerCount": 2, + "peers": { + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65002, + "localAs": 65001, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.2.2": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "pfxRcd": 1, + "state": "Established", + }, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge" + + def _bgp_check_neighbors(): + output = json.loads(r1.vtysh_cmd("show bgp neighbors json")) + expected = { + "192.168.1.2": { + "nbrCommonAdmin": True, + "nbrConfedExternalLink": True, + "hostname": "r2", + }, + "192.168.2.2": { + "nbrCommonAdmin": True, + "nbrConfedExternalLink": True, + "hostname": "r3", + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_neighbors) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't see neighbors to be in BGP confederation" + + def _bgp_check_routes(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "172.16.255.254/32": [ + { + "valid": True, + "pathFrom": "external", + "path": "(65003)", + }, + { + "valid": True, + "pathFrom": "external", + "path": "(65002)", + }, + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_routes) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't see routes to be in BGP confederation" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff -Nru frr-8.4.2/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf frr-8.4.4/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,15 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + neighbor 2001:db8:1::2 remote-as external + address-family ipv4 unicast + network 192.168.0.1/32 + no neighbor 2001:db8:1::2 activate + exit-address-family + address-family ipv6 unicast + neighbor 2001:db8:1::2 activate + network 2001:db8::1/128 + exit-address-family +! diff -Nru frr-8.4.2/tests/topotests/bgp_prefix_list_any/r1/zebra.conf frr-8.4.4/tests/topotests/bgp_prefix_list_any/r1/zebra.conf --- frr-8.4.2/tests/topotests/bgp_prefix_list_any/r1/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_prefix_list_any/r1/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,5 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 + ipv6 address 2001:db8:1::1/64 +! diff -Nru frr-8.4.2/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf frr-8.4.4/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,50 @@ +! +debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 2001:db8:1::1 remote-as external + address-family ipv4 unicast + network 10.10.10.1/32 + network 10.10.10.2/32 + network 10.10.10.3/32 + network 10.10.10.10/32 + no neighbor 2001:db8:1::1 activate + neighbor 192.168.1.1 route-map r1-v4 out + exit-address-family + address-family ipv6 unicast + network 2001:db8:10::1/128 + network 2001:db8:10::2/128 + network 2001:db8:10::3/128 + network 2001:db8:10::10/128 + neighbor 2001:db8:1::1 activate + neighbor 2001:db8:1::1 route-map r1-v6 out + exit-address-family +! +ip prefix-list r1-1 seq 5 permit 10.10.10.1/32 +ip prefix-list r1-1 seq 10 permit 10.10.10.2/32 +ip prefix-list r1-1 seq 15 permit 10.10.10.3/32 +ip prefix-list r1-2 seq 5 permit 10.10.10.10/32 +! +ipv6 prefix-list r1-1 seq 5 permit 2001:db8:10::1/128 +ipv6 prefix-list r1-1 seq 10 permit 2001:db8:10::2/128 +ipv6 prefix-list r1-1 seq 15 permit 2001:db8:10::3/128 +ipv6 prefix-list r1-2 seq 5 permit 2001:db8:10::10/128 +! +route-map r1-v4 permit 10 + match ip address prefix-list r1-1 +exit +! +route-map r1-v4 permit 20 + match ip address prefix-list r1-2 +exit +! +route-map r1-v6 permit 10 + match ipv6 address prefix-list r1-1 +exit +! +route-map r1-v6 permit 20 + match ipv6 address prefix-list r1-2 +exit diff -Nru frr-8.4.2/tests/topotests/bgp_prefix_list_any/r2/zebra.conf frr-8.4.4/tests/topotests/bgp_prefix_list_any/r2/zebra.conf --- frr-8.4.2/tests/topotests/bgp_prefix_list_any/r2/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_prefix_list_any/r2/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,5 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 + ipv6 address 2001:db8:1::2/64 +! diff -Nru frr-8.4.2/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py frr-8.4.4/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py --- frr-8.4.2/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if route-map works correctly when modifying prefix-list +from deny to permit with any, and vice-versa. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_map_prefix_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_prefixes_sent(count): + output = json.loads(r2.vtysh_cmd("show bgp summary json")) + expected = { + "ipv4Unicast": { + "peers": {"192.168.1.1": {"pfxSnt": count, "state": "Established"}} + }, + "ipv6Unicast": { + "peers": {"2001:db8:1::1": {"pfxSnt": count, "state": "Established"}} + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_prefixes_sent, 4) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge initial topology" + + r2.vtysh_cmd( + """ + configure terminal + ip prefix-list r1-2 seq 5 deny any + ipv6 prefix-list r1-2 seq 5 deny any + """ + ) + + test_func = functools.partial(_bgp_prefixes_sent, 3) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Only 3 prefixes MUST be advertised, seeing more" + + r2.vtysh_cmd( + """ + configure terminal + ip prefix-list r1-2 seq 5 permit 10.10.10.10/32 + ipv6 prefix-list r1-2 seq 5 permit 2001:db8:10::10/128 + """ + ) + + test_func = functools.partial(_bgp_prefixes_sent, 4) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "More or less prefixes advertised to r1, MUST be 4" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff -Nru frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r1/bgpd.conf frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r1/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r1/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r1/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,24 @@ +! +debug bgp updates +debug bgp neighbor +! +bgp route-map delay-timer 5 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + address-family ipv4 unicast + network 10.10.10.1/32 + network 10.10.10.2/32 + network 10.10.10.3/32 + aggregate-address 10.10.10.0/24 summary-only + neighbor 192.168.1.2 unsuppress-map r2 + exit-address-family +! +ip prefix-list r1 seq 5 permit 10.10.10.1/32 +ip prefix-list r1 seq 10 permit 10.10.10.2/32 +! +route-map r2 permit 10 + match ip address prefix-list r1 +exit diff -Nru frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r1/zebra.conf frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r1/zebra.conf --- frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r1/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r1/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,4 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff -Nru frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r2/bgpd.conf frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r2/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r2/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r2/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,4 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external +! diff -Nru frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r2/zebra.conf frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r2/zebra.conf --- frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/r2/zebra.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/r2/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,4 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! diff -Nru frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py --- frr-8.4.2/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" + +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_map_delay_timer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge_1(): + output = json.loads( + r1.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.1.2 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.0/24": {}, + "10.10.10.1/32": {}, + "10.10.10.2/32": {}, + "10.10.10.3/32": None, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge_1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "10.10.10.3/32 should not be advertised to r2" + + # Set route-map delay-timer to max value and remove 10.10.10.2/32. + # After this, r1 MUST do not announce updates immediately, and wait + # 600 seconds before withdrawing 10.10.10.2/32. + r2.vtysh_cmd( + """ + configure terminal + bgp route-map delay-timer 600 + no ip prefix-list r1 seq 10 permit 10.10.10.2/32 + """ + ) + + def _bgp_converge_2(): + output = json.loads( + r1.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.1.2 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.0/24": {}, + "10.10.10.1/32": {}, + "10.10.10.2/32": None, + "10.10.10.3/32": None, + } + } + return topotest.json_cmp(output, expected) + + # We are checking `not None` here to wait count*wait time and if we have different + # results than expected, it means good - 10.10.10.2/32 wasn't withdrawn immediately. + test_func = functools.partial(_bgp_converge_2) + _, result = topotest.run_and_expect(test_func, not None, count=60, wait=0.5) + assert ( + result is not None + ), "10.10.10.2/32 advertised, but should not be advertised to r2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff -Nru frr-8.4.2/tests/topotests/bgp_route_origin_parser/pe1/bgpd.conf frr-8.4.4/tests/topotests/bgp_route_origin_parser/pe1/bgpd.conf --- frr-8.4.2/tests/topotests/bgp_route_origin_parser/pe1/bgpd.conf 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_origin_parser/pe1/bgpd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,2 @@ +router bgp 65001 + neighbor 192.168.2.1 remote-as external diff -Nru frr-8.4.2/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py frr-8.4.4/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py --- frr-8.4.2/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py 2023-06-16 04:41:18.000000000 +0000 @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later +# +# April 03 2023, Trey Aspelund +# +# Copyright (C) 2023 NVIDIA Corporation +# +# Test if the CLI parser for RT/SoO ecoms correctly +# constrain user input to valid 4-byte ASN values. +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("pe1") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + pe1 = tgen.gears["pe1"] + pe1.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "pe1/bgpd.conf")) + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_origin_parser(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + pe1 = tgen.gears["pe1"] + + def _invalid_soo_accepted(): + pe1.vtysh_cmd( + """ + configure terminal + router bgp 65001 + address-family ipv4 unicast + neighbor 192.168.2.1 soo 4294967296:65 + """ + ) + run_cfg = pe1.vtysh_cmd("show run") + return "soo" in run_cfg + + def _max_soo_accepted(): + pe1.vtysh_cmd( + """ + configure terminal + router bgp 65001 + address-family ipv4 unicast + neighbor 192.168.2.1 soo 4294967295:65 + """ + ) + run_cfg = pe1.vtysh_cmd("show run") + return "soo 4294967295:65" in run_cfg + + def _invalid_rt_accepted(): + pe1.vtysh_cmd( + """ + configure terminal + router bgp 65001 + address-family ipv4 unicast + rt vpn both 4294967296:65 + """ + ) + run_cfg = pe1.vtysh_cmd("show run") + return "rt vpn" in run_cfg + + def _max_rt_accepted(): + pe1.vtysh_cmd( + """ + configure terminal + router bgp 65001 + address-family ipv4 unicast + rt vpn both 4294967295:65 + """ + ) + run_cfg = pe1.vtysh_cmd("show run") + return "rt vpn both 4294967295:65" in run_cfg + + step( + "Configure invalid 4-byte value SoO (4294967296:65), this should not be accepted" + ) + test_func = functools.partial(_invalid_soo_accepted) + _, result = topotest.run_and_expect(test_func, False, count=30, wait=0.5) + assert result is False, "invalid 4-byte value of SoO accepted" + + step("Configure max 4-byte value SoO (4294967295:65), this should be accepted") + test_func = functools.partial(_max_soo_accepted) + _, result = topotest.run_and_expect(test_func, True, count=30, wait=0.5) + assert result is True, "max 4-byte value of SoO not accepted" + + step( + "Configure invalid 4-byte value RT (4294967296:65), this should not be accepted" + ) + test_func = functools.partial(_invalid_rt_accepted) + _, result = topotest.run_and_expect(test_func, False, count=30, wait=0.5) + assert result is False, "invalid 4-byte value of RT accepted" + + step("Configure max 4-byte value RT (4294967295:65), this should be accepted") + test_func = functools.partial(_max_rt_accepted) + _, result = topotest.run_and_expect(test_func, True, count=30, wait=0.5) + assert result is True, "max 4-byte value of RT not accepted" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff -Nru frr-8.4.2/tests/topotests/ospfapi/r1/ospfd.conf frr-8.4.4/tests/topotests/ospfapi/r1/ospfd.conf --- frr-8.4.2/tests/topotests/ospfapi/r1/ospfd.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r1/ospfd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -4,7 +4,12 @@ ip ospf dead-interval 10 ip ospf area 1.2.3.4 ! +interface r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 1.2.3.4 +! router ospf - ospf router-id 192.168.0.1 + ospf router-id 1.0.0.0 capability opaque ! diff -Nru frr-8.4.2/tests/topotests/ospfapi/r1/zebra.conf frr-8.4.4/tests/topotests/ospfapi/r1/zebra.conf --- frr-8.4.2/tests/topotests/ospfapi/r1/zebra.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r1/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -2,3 +2,5 @@ interface r1-eth0 ip address 10.0.1.1/24 ! +interface r1-eth1 + ip address 10.0.4.1/24 diff -Nru frr-8.4.2/tests/topotests/ospfapi/r2/ospfd.conf frr-8.4.4/tests/topotests/ospfapi/r2/ospfd.conf --- frr-8.4.2/tests/topotests/ospfapi/r2/ospfd.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r2/ospfd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -10,6 +10,6 @@ ip ospf area 1.2.3.4 ! router ospf - ospf router-id 192.168.0.2 + ospf router-id 2.0.0.0 capability opaque ! diff -Nru frr-8.4.2/tests/topotests/ospfapi/r3/ospfd.conf frr-8.4.4/tests/topotests/ospfapi/r3/ospfd.conf --- frr-8.4.2/tests/topotests/ospfapi/r3/ospfd.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r3/ospfd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -10,6 +10,6 @@ ip ospf area 1.2.3.4 ! router ospf - ospf router-id 192.168.0.3 + ospf router-id 3.0.0.0 capability opaque ! diff -Nru frr-8.4.2/tests/topotests/ospfapi/r4/ospfd.conf frr-8.4.4/tests/topotests/ospfapi/r4/ospfd.conf --- frr-8.4.2/tests/topotests/ospfapi/r4/ospfd.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r4/ospfd.conf 2023-06-16 04:41:18.000000000 +0000 @@ -4,7 +4,12 @@ ip ospf dead-interval 10 ip ospf area 1.2.3.4 ! +interface r4-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 1.2.3.4 +! router ospf - ospf router-id 192.168.0.4 + ospf router-id 4.0.0.0 capability opaque ! diff -Nru frr-8.4.2/tests/topotests/ospfapi/r4/zebra.conf frr-8.4.4/tests/topotests/ospfapi/r4/zebra.conf --- frr-8.4.2/tests/topotests/ospfapi/r4/zebra.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/r4/zebra.conf 2023-06-16 04:41:18.000000000 +0000 @@ -2,3 +2,5 @@ interface r4-eth0 ip address 10.0.3.4/24 ! +interface r4-eth1 + ip address 10.0.4.4/24 \ No newline at end of file diff -Nru frr-8.4.2/tests/topotests/ospfapi/test_ospf_clientapi.py frr-8.4.4/tests/topotests/ospfapi/test_ospf_clientapi.py --- frr-8.4.2/tests/topotests/ospfapi/test_ospf_clientapi.py 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tests/topotests/ospfapi/test_ospf_clientapi.py 2023-06-16 04:41:18.000000000 +0000 @@ -33,8 +33,16 @@ import pytest -from lib.common_config import retry, run_frr_cmd, step -from lib.micronet import comm_error +from lib.common_config import ( + retry, + run_frr_cmd, + step, + kill_router_daemons, + start_router_daemons, + shutdown_bringup_interface, +) + +from lib.micronet import Timeout, comm_error from lib.topogen import Topogen, TopoRouter from lib.topotest import interface_set_status, json_cmp @@ -56,15 +64,20 @@ # Test Setup # ---------- +# +# r1 - r2 +# | | +# r4 - r3 +# + @pytest.fixture(scope="function", name="tgen") def _tgen(request): "Setup/Teardown the environment and provide tgen argument to tests" nrouters = request.param - if nrouters == 1: - topodef = {"sw1:": ("r1",)} - else: - topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)} + topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)} + if nrouters == 4: + topodef["sw4"] = ("r4", "r1") tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() @@ -107,23 +120,23 @@ def myreadline(f): buf = b"" while True: - # logging.info("READING 1 CHAR") + # logging.debug("READING 1 CHAR") c = f.read(1) if not c: return buf if buf else None buf += c - # logging.info("READ CHAR: '%s'", c) + # logging.debug("READ CHAR: '%s'", c) if c == b"\n": return buf -def _wait_output(p, regex, timeout=120): - retry_until = datetime.now() + timedelta(seconds=timeout) - while datetime.now() < retry_until: +def _wait_output(p, regex, maxwait=120): + timeout = Timeout(maxwait) + while not timeout.is_expired(): # line = p.stdout.readline() line = myreadline(p.stdout) if not line: - assert None, "Timeout waiting for '{}'".format(regex) + assert None, "EOF waiting for '{}'".format(regex) line = line.decode("utf-8") line = line.rstrip() if line: @@ -131,7 +144,9 @@ m = re.search(regex, line) if m: return m - assert None, "Failed to get output withint {}s".format(timeout) + assert None, "Failed to get output matching '{}' withint {} actual {}s".format( + regex, maxwait, timeout.elapsed() + ) # ----- @@ -141,12 +156,13 @@ def _test_reachability(tgen, testbin): waitlist = [ - "192.168.0.1,192.168.0.2,192.168.0.4", - "192.168.0.2,192.168.0.4", - "192.168.0.1,192.168.0.2,192.168.0.4", + "1.0.0.0,2.0.0.0,4.0.0.0", + "2.0.0.0,4.0.0.0", + "1.0.0.0,2.0.0.0,4.0.0.0", ] r2 = tgen.gears["r2"] r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] wait_args = [f"--wait={x}" for x in waitlist] @@ -164,10 +180,12 @@ step("reachable: check for modified reachability") interface_set_status(r2, "r2-eth0", False) + interface_set_status(r4, "r4-eth1", False) _wait_output(p, "SUCCESS: {}".format(waitlist[1])) step("reachable: check for restored reachability") interface_set_status(r2, "r2-eth0", True) + interface_set_status(r4, "r4-eth1", True) _wait_output(p, "SUCCESS: {}".format(waitlist[2])) except Exception as error: logging.error("ERROR: %s", error) @@ -182,16 +200,16 @@ def test_ospf_reachability(tgen): testbin = os.path.join(TESTDIR, "ctester.py") rc, o, e = tgen.gears["r2"].net.cmd_status([testbin, "--help"]) - logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) _test_reachability(tgen, testbin) def _test_router_id(tgen, testbin): r1 = tgen.gears["r1"] waitlist = [ - "192.168.0.1", + "1.0.0.0", "1.1.1.1", - "192.168.0.1", + "1.0.0.0", ] mon_args = [f"--monitor={x}" for x in waitlist] @@ -213,7 +231,7 @@ _wait_output(p, "SUCCESS: {}".format(waitlist[1])) step("router id: check for restored router id") - r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 192.168.0.1") + r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.0.0.0") _wait_output(p, "SUCCESS: {}".format(waitlist[2])) except Exception as error: logging.error("ERROR: %s", error) @@ -228,7 +246,7 @@ def test_ospf_router_id(tgen): testbin = os.path.join(TESTDIR, "ctester.py") rc, o, e = tgen.gears["r1"].net.cmd_status([testbin, "--help"]) - logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) _test_router_id(tgen, testbin) @@ -243,13 +261,13 @@ try: p = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,2,00000202"]) input_dict = { - "routerId": "192.168.0.1", + "routerId": "1.0.0.0", "areas": { "1.2.3.4": { "linkLocalOpaqueLsa": [ { "lsId": "230.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", } ], @@ -265,7 +283,7 @@ "1.2.3.4": [ { "linkStateId": "230.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", "opaqueData": "00000202", }, @@ -285,13 +303,13 @@ p = None p = r1.popen([apibin, "-v", "add,10,1.2.3.4,231,1,00010101"]) input_dict = { - "routerId": "192.168.0.1", + "routerId": "1.0.0.0", "areas": { "1.2.3.4": { "linkLocalOpaqueLsa": [ { "lsId": "230.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", "lsaAge": 3600, } @@ -299,7 +317,7 @@ "areaLocalOpaqueLsa": [ { "lsId": "231.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", }, ], @@ -315,7 +333,7 @@ "1.2.3.4": [ { "linkStateId": "231.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", "opaqueData": "00010101", }, @@ -336,13 +354,13 @@ p = r1.popen([apibin, "-v", "add,11,232,3,deadbeaf01234567"]) input_dict = { - "routerId": "192.168.0.1", + "routerId": "1.0.0.0", "areas": { "1.2.3.4": { "areaLocalOpaqueLsa": [ { "lsId": "231.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", "lsaAge": 3600, }, @@ -352,7 +370,7 @@ "asExternalOpaqueLsa": [ { "lsId": "232.0.0.3", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", }, ], @@ -364,7 +382,7 @@ "asExternalOpaqueLsa": [ { "linkStateId": "232.0.0.3", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", "opaqueData": "deadbeaf01234567", }, @@ -382,11 +400,11 @@ p = None input_dict = { - "routerId": "192.168.0.1", + "routerId": "1.0.0.0", "asExternalOpaqueLsa": [ { "lsId": "232.0.0.3", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", "lsaAge": 3600, }, @@ -400,11 +418,11 @@ # Originate it again p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"]) input_dict = { - "routerId": "192.168.0.1", + "routerId": "1.0.0.0", "asExternalOpaqueLsa": [ { "lsId": "232.0.0.3", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000002", }, ], @@ -415,7 +433,7 @@ "asExternalOpaqueLsa": [ { "linkStateId": "232.0.0.3", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000002", "opaqueData": "ebadf00d", }, @@ -425,6 +443,7 @@ json_cmd = "show ip ospf da opaque-as json" assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None + logging.debug("sending interrupt to writer api client") p.send_signal(signal.SIGINT) time.sleep(2) p.wait() @@ -439,6 +458,7 @@ raise finally: if p: + logging.debug("cleanup: sending interrupt to writer api client") p.terminate() p.wait() @@ -447,7 +467,7 @@ def test_ospf_opaque_add_data3(tgen): apibin = os.path.join(CLIENTDIR, "ospfclient.py") rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) - logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) _test_add_data(tgen, apibin) @@ -459,10 +479,12 @@ p = None pread = None + # Log to our stdin, stderr + pout = open(os.path.join(r1.net.logdir, "r1/add-del.log"), "a+") try: step("reachable: check for add notification") pread = r2.popen( - ["/usr/bin/timeout", "120", apibin, "-v"], + ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"], encoding=None, # don't buffer stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, @@ -492,30 +514,30 @@ "linkLocalOpaqueLsa": [ { "lsId": "230.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "6d5f", + "checksum": "76bf", }, { "lsId": "230.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "8142", + "checksum": "8aa2", }, ], "linkLocalOpaqueLsaCount": 2, "areaLocalOpaqueLsa": [ { "lsId": "231.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "5278", + "checksum": "5bd8", }, { "lsId": "231.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "6d30", + "checksum": "7690", }, ], "areaLocalOpaqueLsaCount": 2, @@ -524,15 +546,15 @@ "asExternalOpaqueLsa": [ { "lsId": "232.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "5575", + "checksum": "5ed5", }, { "lsId": "232.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "d05d", + "checksum": "d9bd", }, ], "asExternalOpaqueLsaCount": 2, @@ -556,17 +578,17 @@ "1.2.3.4": [ { "linkStateId": "230.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "6d5f", + "checksum": "76bf", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "230.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "8142", + "checksum": "8aa2", "length": 24, "opaqueId": 2, "opaqueDataLength": 4, @@ -581,17 +603,17 @@ "1.2.3.4": [ { "linkStateId": "231.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "5278", + "checksum": "5bd8", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "231.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "6d30", + "checksum": "7690", "length": 28, "opaqueDataLength": 8, }, @@ -603,17 +625,17 @@ "asExternalOpaqueLsa": [ { "linkStateId": "232.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "5575", + "checksum": "5ed5", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "232.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "d05d", + "checksum": "d9bd", "length": 24, "opaqueDataLength": 4, }, @@ -655,32 +677,32 @@ "linkLocalOpaqueLsa": [ { "lsId": "230.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "6d5f", + "checksum": "76bf", }, { "lsId": "230.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "lsaAge": 3600, "sequenceNumber": "80000001", - "checksum": "8142", + "checksum": "8aa2", }, ], "linkLocalOpaqueLsaCount": 2, "areaLocalOpaqueLsa": [ { "lsId": "231.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "5278", + "checksum": "5bd8", }, { "lsId": "231.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "lsaAge": 3600, "sequenceNumber": "80000002", - "checksum": "4682", + "checksum": "4fe2", }, ], "areaLocalOpaqueLsaCount": 2, @@ -689,16 +711,16 @@ "asExternalOpaqueLsa": [ { "lsId": "232.0.0.1", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "lsaAge": 3600, "sequenceNumber": "80000001", - "checksum": "5575", + "checksum": "5ed5", }, { "lsId": "232.0.0.2", - "advertisedRouter": "192.168.0.1", + "advertisedRouter": "1.0.0.0", "sequenceNumber": "80000001", - "checksum": "d05d", + "checksum": "d9bd", }, ], "asExternalOpaqueLsaCount": 2, @@ -716,18 +738,18 @@ "1.2.3.4": [ { "linkStateId": "230.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "6d5f", + "checksum": "76bf", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "230.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "8142", + "checksum": "8aa2", "length": 24, "opaqueId": 2, "opaqueDataLength": 4, @@ -742,18 +764,18 @@ "1.2.3.4": [ { "linkStateId": "231.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "5278", + "checksum": "5bd8", "length": 20, "opaqueDataLength": 0, }, { "lsaAge": 3600, "linkStateId": "231.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000002", - "checksum": "4682", + "checksum": "4fe2", # data removed "length": 20, "opaqueDataLength": 0, @@ -766,18 +788,18 @@ "asExternalOpaqueLsa": [ { "linkStateId": "232.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "5575", + "checksum": "5ed5", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "232.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "d05d", + "checksum": "d9bd", "length": 24, "opaqueDataLength": 4, }, @@ -808,19 +830,19 @@ "1.2.3.4": [ { "linkStateId": "230.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "6d5f", + "checksum": "76bf", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "230.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "8142", + "checksum": "8aa2", "length": 24, "opaqueId": 2, "opaqueDataLength": 4, @@ -836,18 +858,18 @@ { "lsaAge": 3600, "linkStateId": "231.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "checksum": "5278", + "checksum": "5bd8", "length": 20, "opaqueDataLength": 0, }, { "lsaAge": 3600, "linkStateId": "231.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000002", - "checksum": "4682", + "checksum": "4fe2", # data removed "length": 20, "opaqueDataLength": 0, @@ -860,19 +882,19 @@ "asExternalOpaqueLsa": [ { "linkStateId": "232.0.0.1", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "5575", + "checksum": "5ed5", "length": 20, "opaqueDataLength": 0, }, { "linkStateId": "232.0.0.2", - "advertisingRouter": "192.168.0.1", + "advertisingRouter": "1.0.0.0", "lsaAge": 3600, "lsaSeqNumber": "80000001", - "checksum": "d05d", + "checksum": "d9bd", "length": 24, "opaqueDataLength": 4, }, @@ -931,10 +953,195 @@ def test_ospf_opaque_delete_data3(tgen): apibin = os.path.join(CLIENTDIR, "ospfclient.py") rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) - logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) _test_opaque_add_del(tgen, apibin) +def _test_opaque_add_restart_add(tgen, apibin): + "Test adding an opaque LSA and then restarting ospfd" + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + p = None + pread = None + # Log to our stdin, stderr + pout = open(os.path.join(r1.net.logdir, "r1/add-del.log"), "a+") + try: + step("reachable: check for add notification") + 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,10,1.2.3.4,231,1", + "add,10,1.2.3.4,231,1,feedaceebeef", + "wait, 5", + "add,10,1.2.3.4,231,1,feedaceedeadbeef", + "wait, 5", + "add,10,1.2.3.4,231,1,feedaceebaddbeef", + "wait, 5", + ] + ) + add_input_dict = { + "areas": { + "1.2.3.4": { + "areaLocalOpaqueLsa": [ + { + "lsId": "231.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000004", + "checksum": "3128", + }, + ], + "areaLocalOpaqueLsaCount": 1, + }, + }, + } + step("Check for add LSAs") + json_cmd = "show ip ospf da json" + assert verify_ospf_database(tgen, r1, add_input_dict, json_cmd) is None + assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None + + step("Shutdown the interface on r1 to isolate it for r2") + shutdown_bringup_interface(tgen, "r1", "r1-eth0", False) + + time.sleep(2) + step("Reset the client") + p.send_signal(signal.SIGINT) + time.sleep(2) + p.wait() + p = None + + step("Kill ospfd on R1") + kill_router_daemons(tgen, "r1", ["ospfd"]) + time.sleep(2) + + step("Bring ospfd on R1 back up") + start_router_daemons(tgen, "r1", ["ospfd"]) + + p = r1.popen( + [ + apibin, + "-v", + "add,10,1.2.3.4,231,1", + "add,10,1.2.3.4,231,1,feedaceecafebeef", + "wait, 5", + ] + ) + + step("Bring the interface on r1 back up for connection to r2") + shutdown_bringup_interface(tgen, "r1", "r1-eth0", True) + + step("Verify area opaque LSA refresh") + json_cmd = "show ip ospf da opaque-area json" + add_detail_input_dict = { + "areaLocalOpaqueLsa": { + "areas": { + "1.2.3.4": [ + { + "linkStateId": "231.0.0.1", + "advertisingRouter": "1.0.0.0", + "lsaSeqNumber": "80000005", + "checksum": "a87e", + "length": 28, + "opaqueDataLength": 8, + }, + ], + }, + }, + } + assert verify_ospf_database(tgen, r1, add_detail_input_dict, json_cmd) is None + assert verify_ospf_database(tgen, r2, add_detail_input_dict, json_cmd) is None + + step("Shutdown the interface on r1 to isolate it for r2") + shutdown_bringup_interface(tgen, "r1", "r1-eth0", False) + + time.sleep(2) + step("Reset the client") + p.send_signal(signal.SIGINT) + time.sleep(2) + p.wait() + p = None + + step("Kill ospfd on R1") + kill_router_daemons(tgen, "r1", ["ospfd"]) + time.sleep(2) + + step("Bring ospfd on R1 back up") + start_router_daemons(tgen, "r1", ["ospfd"]) + + step("Bring the interface on r1 back up for connection to r2") + shutdown_bringup_interface(tgen, "r1", "r1-eth0", True) + + step("Verify area opaque LSA Purging") + json_cmd = "show ip ospf da opaque-area json" + add_detail_input_dict = { + "areaLocalOpaqueLsa": { + "areas": { + "1.2.3.4": [ + { + "lsaAge": 3600, + "linkStateId": "231.0.0.1", + "advertisingRouter": "1.0.0.0", + "lsaSeqNumber": "80000005", + "checksum": "a87e", + "length": 28, + "opaqueDataLength": 8, + }, + ], + }, + }, + } + assert verify_ospf_database(tgen, r1, add_detail_input_dict, json_cmd) is None + assert verify_ospf_database(tgen, r2, add_detail_input_dict, json_cmd) is None + step("Verify Area Opaque LSA removal after timeout (60 seconds)") + time.sleep(60) + json_cmd = "show ip ospf da opaque-area json" + timeout_detail_input_dict = { + "areaLocalOpaqueLsa": { + "areas": { + "1.2.3.4": [], + }, + }, + } + assert ( + verify_ospf_database(tgen, r1, timeout_detail_input_dict, json_cmd) is None + ) + assert ( + verify_ospf_database(tgen, r2, timeout_detail_input_dict, json_cmd) is None + ) + + 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_restart(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_add_restart_add(tgen, apibin) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff -Nru frr-8.4.2/tools/etc/rsyslog.d/45-frr.conf frr-8.4.4/tools/etc/rsyslog.d/45-frr.conf --- frr-8.4.2/tools/etc/rsyslog.d/45-frr.conf 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tools/etc/rsyslog.d/45-frr.conf 2023-06-16 04:41:18.000000000 +0000 @@ -17,6 +17,7 @@ $programname == 'pimd' or $programname == 'pim6d' or $programname == 'pathd' or + $programname == 'pbrd' or $programname == 'ripd' or $programname == 'ripngd' or $programname == 'vrrpd' or @@ -38,6 +39,7 @@ $programname == 'pimd' or $programname == 'pim6d' or $programname == 'pathd' or + $programname == 'pbrd' or $programname == 'ripd' or $programname == 'ripngd' or $programname == 'vrrpd' or diff -Nru frr-8.4.2/tools/frr-reload.py frr-8.4.4/tools/frr-reload.py --- frr-8.4.2/tools/frr-reload.py 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/tools/frr-reload.py 2023-06-16 04:41:18.000000000 +0000 @@ -804,6 +804,8 @@ # remote-as config. pg_dict = dict() + found_pg_cmd = False + # Find all peer-group commands; create dict of each peer-group # to store assoicated neighbor as value for ctx_keys, line in lines_to_add: @@ -825,6 +827,10 @@ } found_pg_cmd = True + # Do nothing if there is no any "peer-group" + if found_pg_cmd is False: + return + # Find peer-group with remote-as command, also search neighbor # associated to peer-group and store into peer-group dict for ctx_keys, line in lines_to_add: @@ -866,7 +872,7 @@ for pg in pg_dict[ctx_keys[0]]: if pg_dict[ctx_keys[0]][pg]["remoteas"] == True: for nbr in pg_dict[ctx_keys[0]][pg]["nbr"]: - if re_nbr_rmtas.group(1) in nbr: + if re_nbr_rmtas.group(1) == nbr: lines_to_del_from_add.append((ctx_keys, line)) for ctx_keys, line in lines_to_del_from_add: @@ -1490,10 +1496,17 @@ lines_to_add_to_del.append((tmp_ctx_keys, line)) for (ctx_keys, line) in lines_to_del_to_del: - lines_to_del.remove((ctx_keys, line)) + try: + lines_to_del.remove((ctx_keys, line)) + except ValueError: + pass for (ctx_keys, line) in lines_to_add_to_del: - lines_to_add.remove((ctx_keys, line)) + try: + lines_to_add.remove((ctx_keys, line)) + except ValueError: + pass + return (lines_to_add, lines_to_del) diff -Nru frr-8.4.2/vrrpd/vrrp.c frr-8.4.4/vrrpd/vrrp.c --- frr-8.4.2/vrrpd/vrrp.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/vrrpd/vrrp.c 2023-06-16 04:41:18.000000000 +0000 @@ -669,6 +669,9 @@ struct vrrp_vrouter *vrrp_lookup(const struct interface *ifp, uint8_t vrid) { + if (!ifp) + return NULL; + struct vrrp_vrouter vr; vr.vrid = vrid; diff -Nru frr-8.4.2/vtysh/vtysh.h frr-8.4.4/vtysh/vtysh.h --- frr-8.4.2/vtysh/vtysh.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/vtysh/vtysh.h 2023-06-16 04:41:18.000000000 +0000 @@ -59,7 +59,7 @@ * things like prefix lists are not even initialised) */ #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD #define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA -#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD +#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD #define VTYSH_INTERFACE_SUBSET \ VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \ VTYSH_ISISD | VTYSH_PIMD | VTYSH_PIM6D | VTYSH_NHRPD | \ diff -Nru frr-8.4.2/vtysh/vtysh_user.c frr-8.4.4/vtysh/vtysh_user.c --- frr-8.4.2/vtysh/vtysh_user.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/vtysh/vtysh_user.c 2023-06-16 04:41:18.000000000 +0000 @@ -57,7 +57,7 @@ static int vtysh_pam(const char *user) { - int ret; + int ret, second_ret; pam_handle_t *pamh = NULL; /* Start PAM. */ @@ -71,15 +71,18 @@ fprintf(stderr, "vtysh_pam: Failure to initialize pam: %s(%d)", pam_strerror(pamh, ret), ret); - if (pam_acct_mgmt(pamh, 0) != PAM_SUCCESS) + second_ret = pam_acct_mgmt(pamh, 0); + if (second_ret != PAM_SUCCESS) fprintf(stderr, "%s: Failed in account validation: %s(%d)", - __func__, pam_strerror(pamh, ret), ret); + __func__, pam_strerror(pamh, second_ret), second_ret); /* close Linux-PAM */ - if (pam_end(pamh, ret) != PAM_SUCCESS) { + second_ret = pam_end(pamh, ret); + if (second_ret != PAM_SUCCESS) { pamh = NULL; - fprintf(stderr, "vtysh_pam: failed to release authenticator: %s(%d)\n", - pam_strerror(pamh, ret), ret); + fprintf(stderr, + "vtysh_pam: failed to release authenticator: %s(%d)\n", + pam_strerror(pamh, second_ret), second_ret); exit(1); } diff -Nru frr-8.4.2/zebra/if_netlink.c frr-8.4.4/zebra/if_netlink.c --- frr-8.4.2/zebra/if_netlink.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/if_netlink.c 2023-06-16 04:41:18.000000000 +0000 @@ -1996,7 +1996,15 @@ if (tb[IFLA_PROTO_DOWN]) netlink_proc_dplane_if_protodown(ifp->info, tb); - + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + zif = ifp->info; + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } } else if (ifp->vrf->vrf_id != vrf_id) { /* VRF change for an interface. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -2132,6 +2140,14 @@ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK update for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } } zif = ifp->info; diff -Nru frr-8.4.2/zebra/main.c frr-8.4.4/zebra/main.c --- frr-8.4.2/zebra/main.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/main.c 2023-06-16 04:41:18.000000000 +0000 @@ -204,6 +204,8 @@ */ zebra_routemap_finish(); + rib_update_finish(); + list_delete(&zrouter.client_list); /* Indicate that all new dplane work has been enqueued. When that diff -Nru frr-8.4.2/zebra/rib.h frr-8.4.4/zebra/rib.h --- frr-8.4.2/zebra/rib.h 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/rib.h 2023-06-16 04:41:18.000000000 +0000 @@ -331,6 +331,7 @@ RIB_UPDATE_OTHER, RIB_UPDATE_MAX }; +void rib_update_finish(void); int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new_nhghe); @@ -475,6 +476,13 @@ extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, bool rt_delete); +/* + * rib_find_rn_from_ctx + * + * Returns a lock increased route_node for the appropriate + * table and prefix specified by the context. Developer + * should unlock the node when done. + */ extern struct route_node * rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx); diff -Nru frr-8.4.2/zebra/zapi_msg.c frr-8.4.4/zebra/zapi_msg.c --- frr-8.4.2/zebra/zapi_msg.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/zapi_msg.c 2023-06-16 04:41:18.000000000 +0000 @@ -818,11 +818,17 @@ int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, enum zapi_route_notify_owner note) { - return (route_notify_internal( - rib_find_rn_from_ctx(ctx), dplane_ctx_get_type(ctx), - dplane_ctx_get_instance(ctx), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), note, dplane_ctx_get_afi(ctx), - dplane_ctx_get_safi(ctx))); + int result; + struct route_node *rn = rib_find_rn_from_ctx(ctx); + + result = route_notify_internal( + rn, dplane_ctx_get_type(ctx), dplane_ctx_get_instance(ctx), + dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx), note, + dplane_ctx_get_afi(ctx), dplane_ctx_get_safi(ctx)); + + route_unlock_node(rn); + + return result; } static void zread_route_notify_request(ZAPI_HANDLER_ARGS) diff -Nru frr-8.4.2/zebra/zebra_dplane.c frr-8.4.4/zebra/zebra_dplane.c --- frr-8.4.2/zebra/zebra_dplane.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/zebra_dplane.c 2023-06-16 04:41:18.000000000 +0000 @@ -3479,6 +3479,11 @@ NEXTHOP_FLAG_FIB); } + if ((op == DPLANE_OP_ROUTE_UPDATE) && old_re && re && + (old_re != re) && + !CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + dplane_ctx_free(&ctx); return ZEBRA_DPLANE_REQUEST_SUCCESS; } @@ -6500,10 +6505,6 @@ zdplane_info.dg_run = false; - if (zdplane_info.dg_t_update) - thread_cancel_async(zdplane_info.dg_t_update->master, - &zdplane_info.dg_t_update, NULL); - frr_pthread_stop(zdplane_info.dg_pthread, NULL); /* Destroy pthread */ diff -Nru frr-8.4.2/zebra/zebra_evpn_mac.c frr-8.4.4/zebra/zebra_evpn_mac.c --- frr-8.4.2/zebra/zebra_evpn_mac.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/zebra_evpn_mac.c 2023-06-16 04:41:18.000000000 +0000 @@ -1034,12 +1034,11 @@ char flag_buf[MACIP_BUF_SIZE]; zlog_debug( - "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", + "Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", zclient_evpn_dump_macip_flags(flags, flag_buf, sizeof(flag_buf)), - macaddr, ip, seq, vni, - es ? es->esi_str : "-", + state, macaddr, ip, seq, vni, es ? es->esi_str : "-", zebra_route_string(client->proto)); } @@ -1318,16 +1317,26 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t flags, bool force) { + int state = ZEBRA_NEIGH_ACTIVE; + if (!force) { if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE)) /* the host was not advertised - nothing to delete */ return 0; + + /* MAC is LOCAL and DUP_DETECTED, this local mobility event + * is not known to bgpd. Upon receiving local delete + * ask bgp to reinstall the best route (remote entry). + */ + if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL) && + CHECK_FLAG(flags, ZEBRA_MAC_DUPLICATE)) + state = ZEBRA_NEIGH_INACTIVE; } return zebra_evpn_macip_send_msg_to_client( - vni, macaddr, NULL, 0 /* flags */, 0 /* seq */, - ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL); + vni, macaddr, NULL, 0 /* flags */, 0 /* seq */, state, NULL, + ZEBRA_MACIP_DEL); } /* @@ -2439,7 +2448,7 @@ /* Remove MAC from BGP. */ zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags, - false /* force */); + clear_static /* force */); zebra_evpn_es_mac_deref_entry(mac); diff -Nru frr-8.4.2/zebra/zebra_netns_notify.c frr-8.4.4/zebra/zebra_netns_notify.c --- frr-8.4.2/zebra/zebra_netns_notify.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/zebra_netns_notify.c 2023-06-16 04:41:18.000000000 +0000 @@ -178,6 +178,17 @@ if_down(ifp); } + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, false); + if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, IFINDEX_INTERNAL, + false); + /* Special handling for bridge or VxLAN interfaces. */ + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2_bridge_del(ifp); + else if (IS_ZEBRA_IF_VXLAN(ifp)) + zebra_l2_vxlanif_del(ifp); + UNSET_FLAG(ifp->flags, IFF_UP); if_delete_update(&ifp); } diff -Nru frr-8.4.2/zebra/zebra_rib.c frr-8.4.4/zebra/zebra_rib.c --- frr-8.4.2/zebra/zebra_rib.c 2023-01-10 15:02:10.000000000 +0000 +++ frr-8.4.4/zebra/zebra_rib.c 2023-06-16 04:41:18.000000000 +0000 @@ -3800,7 +3800,9 @@ rmap_name = zebra_get_import_table_route_map(afi, re->table); zebra_add_import_table_entry(zvrf, rn, re, rmap_name); - } else if (process) + } + + if (process) rib_queue_add(rn); } @@ -3875,11 +3877,9 @@ zlog_debug("%s(%u):%pRN: Freeing route rn %p, re %p (%s)", vrf_id_to_name(re->vrf_id), re->vrf_id, rn, rn, re, zebra_route_string(re->type)); - - rib_unlink(rn, re); - } else { - rib_queue_add(rn); } + + rib_queue_add(rn); } /* @@ -4365,6 +4365,22 @@ */ static struct thread *t_rib_update_threads[RIB_UPDATE_MAX]; +void rib_update_finish(void) +{ + int i; + + for (i = RIB_UPDATE_KERNEL; i < RIB_UPDATE_MAX; i++) { + if (thread_is_scheduled(t_rib_update_threads[i])) { + struct rib_update_ctx *ctx; + + ctx = THREAD_ARG(t_rib_update_threads[i]); + + rib_update_ctx_fini(&ctx); + THREAD_OFF(t_rib_update_threads[i]); + } + } +} + /* Schedule a RIB update event for all vrfs */ void rib_update(enum rib_update_event event) { @@ -4373,6 +4389,9 @@ if (thread_is_scheduled(t_rib_update_threads[event])) return; + if (zebra_router_in_shutdown()) + return; + ctx = rib_update_ctx_init(0, event); ctx->vrf_all = true; @@ -4568,6 +4587,21 @@ struct dplane_ctx_q ctxlist; bool shut_p = false; +#ifdef HAVE_SCRIPTING + char *script_name = + frrscript_names_get_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL); + + int ret = 1; + struct frrscript *fs = NULL; + + if (script_name) { + fs = frrscript_new(script_name); + if (fs) + ret = frrscript_load(fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL, + NULL); + } +#endif /* HAVE_SCRIPTING */ + /* Dequeue a list of completed updates with one lock/unlock cycle */ do { @@ -4601,24 +4635,7 @@ continue; } -#ifdef HAVE_SCRIPTING - char *script_name = frrscript_names_get_script_name( - ZEBRA_ON_RIB_PROCESS_HOOK_CALL); - - int ret = 1; - struct frrscript *fs; - - if (script_name) { - fs = frrscript_new(script_name); - if (fs) - ret = frrscript_load( - fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL, - NULL); - } -#endif /* HAVE_SCRIPTING */ - while (ctx) { - #ifdef HAVE_SCRIPTING if (ret == 0) frrscript_call(fs, @@ -4728,6 +4745,11 @@ } } while (1); + +#ifdef HAVE_SCRIPTING + if (fs) + frrscript_delete(fs); +#endif } /*