]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / bgpd / bgp_route.c
index 2595bd1d36b628a87e468878017c409fba507666..ba19b3bb2a61df62b83e62cb0a84efa14eab125b 100644 (file)
@@ -1,22 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* BGP routing information
  * Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
  * Copyright (C) 2016 Job Snijders <job@instituut.net>
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -72,7 +57,6 @@
 #include "bgpd/bgp_addpath.h"
 #include "bgpd/bgp_mac.h"
 #include "bgpd/bgp_network.h"
-#include "bgpd/bgp_orr.h"
 #include "bgpd/bgp_trace.h"
 #include "bgpd/bgp_rpki.h"
 
@@ -566,7 +550,6 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
                             enum bgp_path_selection_reason *reason)
 {
        const struct prefix *new_p;
-       struct prefix exist_p;
        struct attr *newattr, *existattr;
        enum bgp_peer_sort new_sort;
        enum bgp_peer_sort exist_sort;
@@ -599,11 +582,6 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
        bool new_origin, exist_origin;
        struct bgp_path_info *bpi_ultimate;
 
-       struct bgp_orr_group *orr_group = NULL;
-       struct listnode *node;
-       struct bgp_orr_igp_metric *igp_metric = NULL;
-       struct list *orr_group_igp_metric_info = NULL;
-
        *paths_eq = 0;
 
        /* 0. Null check. */
@@ -1139,49 +1117,6 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
        if (exist->extra)
                existm = exist->extra->igpmetric;
 
-       if (new->peer->orr_group_name[afi][safi]) {
-               ret = str2prefix(new->peer->host, &exist_p);
-               orr_group = bgp_orr_group_lookup_by_name(
-                       bgp, afi, safi, new->peer->orr_group_name[afi][safi]);
-               if (orr_group) {
-                       orr_group_igp_metric_info = orr_group->igp_metric_info;
-                       if (orr_group_igp_metric_info) {
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            orr_group_igp_metric_info, node,
-                                            igp_metric)) {
-                                       if (ret &&
-                                           prefix_cmp(&exist_p,
-                                                      &igp_metric->prefix) ==
-                                                   0) {
-                                               newm = igp_metric->igp_metric;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-       if (exist->peer->orr_group_name[afi][safi]) {
-               ret = str2prefix(exist->peer->host, &exist_p);
-               orr_group = bgp_orr_group_lookup_by_name(
-                       bgp, afi, safi, exist->peer->orr_group_name[afi][safi]);
-               if (orr_group) {
-                       orr_group_igp_metric_info = orr_group->igp_metric_info;
-                       if (orr_group_igp_metric_info) {
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            orr_group_igp_metric_info, node,
-                                            igp_metric)) {
-                                       if (ret &&
-                                           prefix_cmp(&exist_p,
-                                                      &igp_metric->prefix) ==
-                                                   0) {
-                                               existm = igp_metric->igp_metric;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-
        if (newm < existm) {
                if (debug && peer_sort_ret < 0)
                        zlog_debug(
@@ -2323,8 +2258,12 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                        && peer->shared_network
                        && (from == bgp->peer_self
                            || peer->sort == BGP_PEER_EBGP))) {
-                       attr->mp_nexthop_len =
-                               BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
+                       if (safi == SAFI_MPLS_VPN)
+                               attr->mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
+                       else
+                               attr->mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
                }
 
                /* Clear off link-local nexthop in source, whenever it is not
@@ -4003,11 +3942,11 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
        return false;
 }
 
-int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
-              struct attr *attr, afi_t afi, safi_t safi, int type,
-              int sub_type, struct prefix_rd *prd, mpls_label_t *label,
-              uint32_t num_labels, int soft_reconfig,
-              struct bgp_route_evpn *evpn)
+void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
+               struct attr *attr, afi_t afi, safi_t safi, int type,
+               int sub_type, struct prefix_rd *prd, mpls_label_t *label,
+               uint32_t num_labels, int soft_reconfig,
+               struct bgp_route_evpn *evpn)
 {
        int ret;
        int aspath_loop_count = 0;
@@ -4383,7 +4322,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        bgp_dest_unlock_node(dest);
                        bgp_attr_unintern(&attr_new);
 
-                       return 0;
+                       return;
                }
 
                /* Withdraw/Announce before we fully processed the withdraw */
@@ -4502,8 +4441,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                                                bgp_evpn_unimport_route(
                                                        bgp, afi, safi, p, pi);
                                        else /* SAFI_MPLS_VPN */
-                                               vpn_leak_to_vrf_withdraw(bgp,
-                                                                        pi);
+                                               vpn_leak_to_vrf_withdraw(pi);
                                }
                        }
                }
@@ -4597,7 +4535,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        ret = bgp_damp_update(pi, dest, afi, safi);
                        if (ret == BGP_DAMP_SUPPRESSED) {
                                bgp_dest_unlock_node(dest);
-                               return 0;
+                               return;
                        }
                }
 
@@ -4717,7 +4655,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        bgp_unlink_nexthop(pi);
                        bgp_path_info_delete(dest, pi);
                }
-               return 0;
+               return;
        } // End of implicit withdraw
 
        /* Received Logging. */
@@ -4880,7 +4818,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                bgp_path_info_delete(dest, new);
        }
 
-       return 0;
+       return;
 
 /* This BGP update is filtered.  Log the reason then update BGP
    entry.  */
@@ -4923,7 +4861,7 @@ filtered:
                if ((SAFI_MPLS_VPN == safi)
                    && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
 
-                       vpn_leak_to_vrf_withdraw(bgp, pi);
+                       vpn_leak_to_vrf_withdraw(pi);
                }
 
                bgp_rib_remove(dest, pi, peer, afi, safi);
@@ -4943,13 +4881,14 @@ filtered:
        }
 #endif
 
-       return 0;
+       return;
 }
 
-int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
-                struct attr *attr, afi_t afi, safi_t safi, int type,
-                int sub_type, struct prefix_rd *prd, mpls_label_t *label,
-                uint32_t num_labels, struct bgp_route_evpn *evpn)
+void bgp_withdraw(struct peer *peer, const struct prefix *p,
+                 uint32_t addpath_id, struct attr *attr, afi_t afi,
+                 safi_t safi, int type, int sub_type, struct prefix_rd *prd,
+                 mpls_label_t *label, uint32_t num_labels,
+                 struct bgp_route_evpn *evpn)
 {
        struct bgp *bgp;
        char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -4994,7 +4933,7 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                                        peer->host, pfx_buf);
                        }
                        bgp_dest_unlock_node(dest);
-                       return 0;
+                       return;
                }
 
        /* Lookup withdrawn route. */
@@ -5024,7 +4963,7 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                if ((SAFI_MPLS_VPN == safi)
                    && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
 
-                       vpn_leak_to_vrf_withdraw(bgp, pi);
+                       vpn_leak_to_vrf_withdraw(pi);
                }
        } else if (bgp_debug_update(peer, p, NULL, 1)) {
                bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
@@ -5036,7 +4975,7 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        /* Unlock bgp_node_get() lock. */
        bgp_dest_unlock_node(dest);
 
-       return 0;
+       return;
 }
 
 void bgp_default_originate(struct peer *peer, afi_t afi, safi_t safi,
@@ -5168,10 +5107,10 @@ static void bgp_soft_reconfig_table_flag(struct bgp_table *table, bool flag)
        }
 }
 
-static int bgp_soft_reconfig_table_update(struct peer *peer,
-                                         struct bgp_dest *dest,
-                                         struct bgp_adj_in *ain, afi_t afi,
-                                         safi_t safi, struct prefix_rd *prd)
+static void bgp_soft_reconfig_table_update(struct peer *peer,
+                                          struct bgp_dest *dest,
+                                          struct bgp_adj_in *ain, afi_t afi,
+                                          safi_t safi, struct prefix_rd *prd)
 {
        struct bgp_path_info *pi;
        uint32_t num_labels = 0;
@@ -5192,17 +5131,15 @@ static int bgp_soft_reconfig_table_update(struct peer *peer,
        else
                memset(&evpn, 0, sizeof(evpn));
 
-       return bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
-                         ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
-                         BGP_ROUTE_NORMAL, prd, label_pnt, num_labels, 1,
-                         &evpn);
+       bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
+                  ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd,
+                  label_pnt, num_labels, 1, &evpn);
 }
 
 static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                                    struct bgp_table *table,
                                    struct prefix_rd *prd)
 {
-       int ret;
        struct bgp_dest *dest;
        struct bgp_adj_in *ain;
 
@@ -5214,13 +5151,8 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                        if (ain->peer != peer)
                                continue;
 
-                       ret = bgp_soft_reconfig_table_update(peer, dest, ain,
-                                                            afi, safi, prd);
-
-                       if (ret < 0) {
-                               bgp_dest_unlock_node(dest);
-                               return;
-                       }
+                       bgp_soft_reconfig_table_update(peer, dest, ain, afi,
+                                                      safi, prd);
                }
 }
 
@@ -5235,7 +5167,6 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
 static void bgp_soft_reconfig_table_task(struct thread *thread)
 {
        uint32_t iter, max_iter;
-       int ret;
        struct bgp_dest *dest;
        struct bgp_adj_in *ain;
        struct peer *peer;
@@ -5268,27 +5199,10 @@ static void bgp_soft_reconfig_table_task(struct thread *thread)
                                if (ain->peer != peer)
                                        continue;
 
-                               ret = bgp_soft_reconfig_table_update(
+                               bgp_soft_reconfig_table_update(
                                        peer, dest, ain, table->afi,
                                        table->safi, prd);
                                iter++;
-
-                               if (ret < 0) {
-                                       bgp_dest_unlock_node(dest);
-                                       listnode_delete(
-                                               table->soft_reconfig_peers,
-                                               peer);
-                                       bgp_announce_route(peer, table->afi,
-                                                          table->safi, false);
-                                       if (list_isempty(
-                                                   table->soft_reconfig_peers)) {
-                                               list_delete(
-                                                       &table->soft_reconfig_peers);
-                                               bgp_soft_reconfig_table_flag(
-                                                       table, false);
-                                               return;
-                                       }
-                               }
                        }
                }
        }
@@ -5489,7 +5403,7 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
                        }
                        if (SAFI_MPLS_VPN == safi &&
                            bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
-                               vpn_leak_to_vrf_withdraw(bgp, pi);
+                               vpn_leak_to_vrf_withdraw(pi);
                        }
 
                        bgp_rib_remove(dest, pi, peer, afi, safi);
@@ -5758,8 +5672,7 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
                                                    BGP_ROUTE_IMPORTED &&
                                            peer->bgp->inst_type ==
                                                    BGP_INSTANCE_TYPE_DEFAULT)
-                                               vpn_leak_to_vrf_withdraw(
-                                                       peer->bgp, pi);
+                                               vpn_leak_to_vrf_withdraw(pi);
 
                                        bgp_rib_remove(rm, pi, peer, afi, safi);
                                        break;
@@ -6005,7 +5918,6 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
        uint8_t *lim;
        struct prefix p;
        int psize;
-       int ret;
        afi_t afi;
        safi_t safi;
        bool addpath_capable;
@@ -6118,23 +6030,18 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
 
                /* Normal process. */
                if (attr)
-                       ret = bgp_update(peer, &p, addpath_id, attr, afi, safi,
-                                        ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                        NULL, NULL, 0, 0, NULL);
+                       bgp_update(peer, &p, addpath_id, attr, afi, safi,
+                                  ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
+                                  NULL, 0, 0, NULL);
                else
-                       ret = bgp_withdraw(peer, &p, addpath_id, attr, afi,
-                                          safi, ZEBRA_ROUTE_BGP,
-                                          BGP_ROUTE_NORMAL, NULL, NULL, 0,
-                                          NULL);
+                       bgp_withdraw(peer, &p, addpath_id, attr, afi, safi,
+                                    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
+                                    NULL, 0, NULL);
 
                /* Do not send BGP notification twice when maximum-prefix count
                 * overflow. */
                if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
                        return BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW;
-
-               /* Address family configuration mismatch. */
-               if (ret < 0)
-                       return BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY;
        }
 
        /* Packet length consistency check. */
@@ -6460,7 +6367,7 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, const struct prefix *p,
 #endif
                if (SAFI_MPLS_VPN == safi
                    && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
-                       vpn_leak_to_vrf_withdraw(bgp, pi);
+                       vpn_leak_to_vrf_withdraw(pi);
                }
                bgp_aggregate_decrement(bgp, p, pi, afi, safi);
                bgp_path_info_delete(dest, pi);
@@ -9529,7 +9436,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
                        json_object_string_add(json_path, "path",
                                               attr->aspath->str);
                else
-                       aspath_print_vty(vty, "%s", attr->aspath, " ");
+                       aspath_print_vty(vty, attr->aspath);
        }
 
        /* Print origin */
@@ -9747,7 +9654,7 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
 
                        /* Print aspath */
                        if (attr->aspath)
-                               aspath_print_vty(vty, "%s", attr->aspath, " ");
+                               aspath_print_vty(vty, attr->aspath);
 
                        /* Print origin */
                        vty_out(vty, "%s", bgp_origin_str[attr->origin]);
@@ -9934,8 +9841,6 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
                if (!json_path) {
                        vty_out(vty, "?");
                } else {
-                       json_object_string_add(json_nexthop, "Error",
-                                              "Unsupported address-family");
                        json_object_string_add(json_nexthop, "error",
                                               "Unsupported address-family");
                }
@@ -10014,7 +9919,7 @@ static void damp_route_vty_out(struct vty *vty, const struct prefix *p,
                                                use_json, NULL));
 
                if (attr->aspath)
-                       aspath_print_vty(vty, "%s", attr->aspath, " ");
+                       aspath_print_vty(vty, attr->aspath);
 
                vty_out(vty, "%s", bgp_origin_str[attr->origin]);
 
@@ -10091,7 +9996,7 @@ static void flap_route_vty_out(struct vty *vty, const struct prefix *p,
                        vty_out(vty, "%*s ", 8, " ");
 
                if (attr->aspath)
-                       aspath_print_vty(vty, "%s", attr->aspath, " ");
+                       aspath_print_vty(vty, attr->aspath);
 
                vty_out(vty, "%s", bgp_origin_str[attr->origin]);
 
@@ -10303,12 +10208,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
                                if (tag_buf[0] != '\0')
                                        vty_out(vty, " VNI %s", tag_buf);
                        } else {
-                               if (tag_buf[0]) {
-                                       json_object_string_add(json_path, "VNI",
-                                                              tag_buf);
+                               if (tag_buf[0])
                                        json_object_string_add(json_path, "vni",
                                                               tag_buf);
-                               }
                        }
                }
        }
@@ -10375,7 +10277,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
                                               attr->aspath->json);
                } else {
                        if (attr->aspath->segments)
-                               aspath_print_vty(vty, "  %s", attr->aspath, "");
+                               vty_out(vty, "  %s", attr->aspath->str);
                        else
                                vty_out(vty, "  Local");
                }
@@ -11669,7 +11571,16 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                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
@@ -12132,9 +12043,16 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
        case SAFI_ENCAP:
        case SAFI_EVPN:
                return (struct prefix_rd *)(bgp_dest_get_prefix(dest));
-       default:
+       case SAFI_UNSPEC:
+       case SAFI_UNICAST:
+       case SAFI_MULTICAST:
+       case SAFI_LABELED_UNICAST:
+       case SAFI_FLOWSPEC:
+       case SAFI_MAX:
                return NULL;
        }
+
+       assert(!"Reached end of function when we were not expecting it");
 }
 
 /* Display specified route of BGP table. */
@@ -12677,7 +12595,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
           |alias ALIAS_NAME\
           |A.B.C.D/M longer-prefixes\
           |X:X::X:X/M longer-prefixes\
-         |optimal-route-reflection [WORD$orr_group_name]\
           |detail-routes$detail_routes\
           ] [json$uj [detail$detail_json] | wide$wide]",
       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
@@ -12727,8 +12644,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
       "Display route and more specific routes\n"
       "IPv6 prefix\n"
       "Display route and more specific routes\n"
-      "Display Optimal Route Reflection RR Clients\n"
-      "ORR Group name\n"
       "Display detailed version of all routes\n"
       JSON_STR
       "Display detailed version of JSON output\n"
@@ -12746,7 +12661,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
        uint16_t show_flags = 0;
        enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
        struct prefix p;
-       bool orr_group = false;
 
        if (uj) {
                argc--;
@@ -12924,18 +12838,12 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                output_arg = &p;
        }
 
-       if (argv_find(argv, argc, "optimal-route-reflection", &idx))
-               orr_group = true;
-
        if (!all) {
                /* show bgp: AFI_IP6, show ip bgp: AFI_IP */
                if (community)
                        return bgp_show_community(vty, bgp, community,
                                                  exact_match, afi, safi,
                                                  show_flags);
-               else if (orr_group)
-                       return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
-                                           show_flags);
                else
                        return bgp_show(vty, bgp, afi, safi, sh_type,
                                        output_arg, show_flags,
@@ -12981,11 +12889,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                                                        vty, abgp, community,
                                                        exact_match, afi, safi,
                                                        show_flags);
-                                       else if (orr_group)
-                                               bgp_show_orr(vty, bgp, afi,
-                                                            safi,
-                                                            orr_group_name,
-                                                            show_flags);
                                        else
                                                bgp_show(vty, abgp, afi, safi,
                                                         sh_type, output_arg,
@@ -13025,11 +12928,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                                                        vty, abgp, community,
                                                        exact_match, afi, safi,
                                                        show_flags);
-                                       else if (orr_group)
-                                               bgp_show_orr(vty, bgp, afi,
-                                                            safi,
-                                                            orr_group_name,
-                                                            show_flags);
                                        else
                                                bgp_show(vty, abgp, afi, safi,
                                                         sh_type, output_arg,
@@ -13379,7 +13277,8 @@ static void bgp_table_stats_walker(struct thread *t)
        case AFI_L2VPN:
                space = EVPN_ROUTE_PREFIXLEN;
                break;
-       default:
+       case AFI_UNSPEC:
+       case AFI_MAX:
                return;
        }
 
@@ -13634,7 +13533,8 @@ static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi,
        case AFI_L2VPN:
                bitlen = EVPN_ROUTE_PREFIXLEN;
                break;
-       default:
+       case AFI_UNSPEC:
+       case AFI_MAX:
                break;
        }
 
@@ -14061,16 +13961,17 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
               const char *rmap_name, json_object *json, json_object *json_ar,
               json_object *json_scode, json_object *json_ocode,
               uint16_t show_flags, int *header1, int *header2, char *rd_str,
-              unsigned long *output_count, unsigned long *filtered_count)
+              const struct prefix *match, unsigned long *output_count,
+              unsigned long *filtered_count)
 {
-       struct bgp_adj_in *ain;
-       struct bgp_adj_out *adj;
+       struct bgp_adj_in *ain = NULL;
+       struct bgp_adj_out *adj = NULL;
        struct bgp_dest *dest;
        struct bgp *bgp;
        struct attr attr;
        int ret;
        struct update_subgroup *subgrp;
-       struct peer_af *paf;
+       struct peer_af *paf = NULL;
        bool route_filtered;
        bool detail = CHECK_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
        bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -14084,6 +13985,98 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
 
        bgp = peer->bgp;
 
+       /* If the user supplied a prefix, look for a matching route instead
+        * of walking the whole table.
+        */
+       if (match) {
+               dest = bgp_node_match(table, match);
+               if (!dest) {
+                       if (!use_json)
+                               vty_out(vty, "Network not in table\n");
+                       return;
+               }
+
+               const struct prefix *rn_p = bgp_dest_get_prefix(dest);
+
+               if (rn_p->prefixlen != match->prefixlen) {
+                       if (!use_json)
+                               vty_out(vty, "Network not in table\n");
+                       bgp_dest_unlock_node(dest);
+                       return;
+               }
+
+               if (type == bgp_show_adj_route_received ||
+                   type == bgp_show_adj_route_filtered) {
+                       for (ain = dest->adj_in; ain; ain = ain->next) {
+                               if (ain->peer == peer) {
+                                       attr = *ain->attr;
+                                       break;
+                               }
+                       }
+                       /* bail out if if adj_out is empty, or
+                        * if the prefix isn't in this peer's
+                        * adj_in
+                        */
+                       if (!ain || ain->peer != peer) {
+                               if (!use_json)
+                                       vty_out(vty, "Network not in table\n");
+                               bgp_dest_unlock_node(dest);
+                               return;
+                       }
+               } else if (type == bgp_show_adj_route_advertised) {
+                       bool peer_found = false;
+
+                       RB_FOREACH (adj, bgp_adj_out_rb, &dest->adj_out) {
+                               SUBGRP_FOREACH_PEER (adj->subgroup, paf) {
+                                       if (paf->peer == peer && adj->attr) {
+                                               attr = *adj->attr;
+                                               peer_found = true;
+                                               break;
+                                       }
+                               }
+                               if (peer_found)
+                                       break;
+                       }
+                       /* bail out if if adj_out is empty, or
+                        * if the prefix isn't in this peer's
+                        * adj_out
+                        */
+                       if (!paf || !peer_found) {
+                               if (!use_json)
+                                       vty_out(vty, "Network not in table\n");
+                               bgp_dest_unlock_node(dest);
+                               return;
+                       }
+               }
+
+               ret = bgp_output_modifier(peer, rn_p, &attr, afi, safi,
+                                         rmap_name);
+
+               if (ret != RMAP_DENY) {
+                       show_adj_route_header(vty, peer, table, header1,
+                                             header2, json, json_scode,
+                                             json_ocode, wide, detail);
+
+                       if (use_json)
+                               json_net = json_object_new_object();
+
+                       bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp,
+                                          afi, safi, json_net,
+                                          BGP_PATH_SHOW_ALL, &display,
+                                          RPKI_NOT_BEING_USED);
+                       if (use_json)
+                               json_object_object_addf(json_ar, json_net,
+                                                       "%pFX", rn_p);
+                       (*output_count)++;
+               } else
+                       (*filtered_count)++;
+
+               bgp_attr_flush(&attr);
+               bgp_dest_unlock_node(dest);
+               return;
+       }
+
+
        subgrp = peer_subgroup(peer, afi, safi);
 
        if (type == bgp_show_adj_route_advertised && subgrp
@@ -14284,6 +14277,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
                                              header2, json, json_scode,
                                              json_ocode, wide, detail);
 
+                       const struct prefix *rn_p = bgp_dest_get_prefix(dest);
+
                        for (pi = bgp_dest_get_bgp_path_info(dest); pi;
                             pi = pi->next) {
                                if (pi->peer != peer)
@@ -14292,10 +14287,23 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
                                if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
                                        continue;
 
-                               route_vty_out_tmp(vty, dest,
-                                                 bgp_dest_get_prefix(dest),
-                                                 pi->attr, safi, use_json,
-                                                 json_ar, wide);
+                               if (detail) {
+                                       if (use_json)
+                                               json_net =
+                                                       json_object_new_object();
+                                       bgp_show_path_info(
+                                               NULL /* prefix_rd */, dest, vty,
+                                               bgp, afi, safi, json_net,
+                                               BGP_PATH_SHOW_BESTPATH,
+                                               &display, RPKI_NOT_BEING_USED);
+                                       if (use_json)
+                                               json_object_object_addf(
+                                                       json_ar, json_net,
+                                                       "%pFX", rn_p);
+                               } else
+                                       route_vty_out_tmp(
+                                               vty, dest, rn_p, pi->attr, safi,
+                                               use_json, json_ar, wide);
                                (*output_count)++;
                        }
                }
@@ -14304,7 +14312,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
 
 static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
                           safi_t safi, enum bgp_show_adj_route_type type,
-                          const char *rmap_name, uint16_t show_flags)
+                          const char *rmap_name, const struct prefix *match,
+                          uint16_t show_flags)
 {
        struct bgp *bgp;
        struct bgp_table *table;
@@ -14430,11 +14439,11 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
 
                        prefix_rd2str(prd, rd_str, sizeof(rd_str));
 
-                       show_adj_route(vty, peer, table, afi, safi, type,
-                                      rmap_name, json, json_routes, json_scode,
-                                      json_ocode, show_flags, &header1,
-                                      &header2, rd_str, &output_count_per_rd,
-                                      &filtered_count_per_rd);
+                       show_adj_route(
+                               vty, peer, table, afi, safi, type, rmap_name,
+                               json, json_routes, json_scode, json_ocode,
+                               show_flags, &header1, &header2, rd_str, match,
+                               &output_count_per_rd, &filtered_count_per_rd);
 
                        /* Don't include an empty RD in the output! */
                        if (json_routes && (output_count_per_rd > 0))
@@ -14447,7 +14456,7 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
        } else
                show_adj_route(vty, peer, table, afi, safi, type, rmap_name,
                               json, json_ar, json_scode, json_ocode,
-                              show_flags, &header1, &header2, rd_str,
+                              show_flags, &header1, &header2, rd_str, match,
                               &output_count, &filtered_count);
 
        if (use_json) {
@@ -14472,7 +14481,7 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
 
                vty_json(vty, json);
        } else if (output_count > 0) {
-               if (filtered_count > 0)
+               if (!match && filtered_count > 0)
                        vty_out(vty,
                                "\nTotal number of prefixes %ld (%ld filtered)\n",
                                output_count, filtered_count);
@@ -14486,7 +14495,7 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
 
 DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        show_ip_bgp_instance_neighbor_bestpath_route_cmd,
-       "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] neighbors <A.B.C.D|X:X::X:X|WORD> bestpath-routes [json$uj | wide$wide]",
+       "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR "]] neighbors <A.B.C.D|X:X::X:X|WORD> bestpath-routes [detail$detail] [json$uj | wide$wide]",
        SHOW_STR
        IP_STR
        BGP_STR
@@ -14498,6 +14507,7 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        "Neighbor to display information about\n"
        "Neighbor on BGP configured interface\n"
        "Display the routes selected by best path\n"
+       "Display detailed version of routes\n"
        JSON_STR
        "Increase table width for longer prefixes\n")
 {
@@ -14511,6 +14521,9 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        int idx = 0;
        uint16_t show_flags = 0;
 
+       if (detail)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
+
        if (uj)
                SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
@@ -14530,13 +14543,13 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        if (!peer)
                return CMD_WARNING;
 
-       return peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+       return peer_adj_routes(vty, peer, afi, safi, type, rmap_name, NULL,
                               show_flags);
 }
 
 DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
       show_ip_bgp_instance_neighbor_advertised_route_cmd,
-      "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR "]] [all$all] neighbors <A.B.C.D|X:X::X:X|WORD> <advertised-routes|received-routes|filtered-routes> [route-map RMAP_NAME$route_map] [detail$detail] [json$uj | wide$wide]",
+      "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR "]] [all$all] neighbors <A.B.C.D|X:X::X:X|WORD> <advertised-routes|received-routes|filtered-routes> [route-map RMAP_NAME$route_map] [<A.B.C.D/M|X:X::X:X/M>$prefix | detail$detail] [json$uj | wide$wide]",
       SHOW_STR
       IP_STR
       BGP_STR
@@ -14553,6 +14566,8 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
       "Display the filtered routes received from neighbor\n"
       "Route-map to modify the attributes\n"
       "Name of the route map\n"
+      "IPv4 prefix\n"
+      "IPv6 prefix\n"
       "Display detailed version of routes\n"
       JSON_STR
       "Increase table width for longer prefixes\n")
@@ -14569,7 +14584,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
        struct listnode *node;
        struct bgp *abgp;
 
-       if (detail)
+       if (detail || prefix_str)
                SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
 
        if (uj) {
@@ -14611,7 +14626,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
 
        if (!all)
                return peer_adj_routes(vty, peer, afi, safi, type, route_map,
-                                      show_flags);
+                                      prefix_str ? prefix : NULL, show_flags);
        if (uj)
                vty_out(vty, "{\n");
 
@@ -14639,7 +14654,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
                                                                 false));
 
                                peer_adj_routes(vty, peer, afi, safi, type,
-                                               route_map, show_flags);
+                                               route_map, prefix, show_flags);
                        }
                }
        } else {
@@ -14663,7 +14678,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
                                                                 false));
 
                                peer_adj_routes(vty, peer, afi, safi, type,
-                                               route_map, show_flags);
+                                               route_map, prefix, show_flags);
                        }
                }
        }