]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
*: Create/Use accessor functions for lock count
[mirror_frr.git] / bgpd / bgp_route.c
index 912615a59ffc4496a469a5476afd9a09c2a5d02e..f998a4d3509a45d2081a2752a8ec797dc6b619db 100644 (file)
@@ -216,7 +216,7 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
                        unsigned refcount;
 
                        bpi = bgp_path_info_lock(bpi);
-                       refcount = bpi->net->lock - 1;
+                       refcount = bgp_dest_get_lock_count(bpi->net) - 1;
                        bgp_dest_unlock_node((struct bgp_dest *)bpi->net);
                        if (!refcount)
                                bpi->net = NULL;
@@ -314,8 +314,8 @@ static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete)
        if (CHECK_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED)) {
                if (BGP_DEBUG(update, UPDATE_OUT))
                        zlog_debug(
-                               "Route %pRN is in workqueue and being processed, not deferred.",
-                               bgp_dest_to_rnode(dest));
+                               "Route %pBD is in workqueue and being processed, not deferred.",
+                               dest);
 
                return 0;
        }
@@ -365,7 +365,7 @@ static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete)
                                        bgp->gr_info[afi][safi].route_list,
                                        dest);
                        if (BGP_DEBUG(update, UPDATE_OUT))
-                               zlog_debug("DEFER route %pRN, dest %p, node %p",
+                               zlog_debug("DEFER route %pBD, dest %p, node %p",
                                           dest, dest, dest->rt_node);
                        return 0;
                }
@@ -1635,7 +1635,6 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
        struct peer *onlypeer;
        struct bgp *bgp;
        struct attr *piattr;
-       char buf[PREFIX_STRLEN];
        route_map_result_t ret;
        int transparent;
        int reflect;
@@ -1671,9 +1670,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                 * though they can have peer pointers that reference other
                 * systems
                 */
-               prefix2str(p, buf, PREFIX_STRLEN);
-               zlog_debug("%s: pfx %s bgp_direct->vpn route peer safe",
-                          __func__, buf);
+               zlog_debug("%s: pfx %pFX bgp_direct->vpn route peer safe",
+                          __func__, p);
                samepeer_safe = 1;
        }
 #endif
@@ -1726,11 +1724,10 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                mpls_label_t label = bgp_adv_label(dest, pi, peer, afi, safi);
                if (!bgp_is_valid_label(&label)) {
                        if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-                               zlog_debug("u%" PRIu64 ":s%" PRIu64" %s/%d is filtered - no label (%p)",
+                               zlog_debug("u%" PRIu64 ":s%" PRIu64
+                                          " %pFX is filtered - no label (%p)",
                                           subgrp->update_group->id, subgrp->id,
-                                          inet_ntop(p->family, &p->u.prefix,
-                                                    buf, SU_ADDRSTRLEN),
-                                          p->prefixlen, &label);
+                                          p, &label);
                        return false;
                }
        }
@@ -1771,9 +1768,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
            && (IPV4_ADDR_SAME(&onlypeer->remote_id, &piattr->originator_id))) {
                if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
                        zlog_debug(
-                               "%s [Update:SEND] %s originator-id is same as remote router-id",
-                               onlypeer->host,
-                               prefix2str(p, buf, sizeof(buf)));
+                               "%s [Update:SEND] %pFX originator-id is same as remote router-id",
+                               onlypeer->host, p);
                return false;
        }
 
@@ -1788,10 +1784,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                                if (bgp_debug_update(NULL, p,
                                                     subgrp->update_group, 0))
                                        zlog_debug(
-                                               "%s [Update:SEND] %s is filtered via ORF",
-                                               peer->host,
-                                               prefix2str(p, buf,
-                                                          sizeof(buf)));
+                                               "%s [Update:SEND] %pFX is filtered via ORF",
+                                               peer->host, p);
                                return false;
                        }
                }
@@ -1799,8 +1793,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
        /* Output filter check. */
        if (bgp_output_filter(peer, p, piattr, afi, safi) == FILTER_DENY) {
                if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-                       zlog_debug("%s [Update:SEND] %s is filtered",
-                                  peer->host, prefix2str(p, buf, sizeof(buf)));
+                       zlog_debug("%s [Update:SEND] %pFX is filtered",
+                                  peer->host, p);
                return false;
        }
 
@@ -1986,8 +1980,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
 
                if (ret == RMAP_DENYMATCH) {
                        if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
-                               zlog_debug("%s [Update:SEND] %s is filtered by route-map",
-                               peer->host, prefix2str(p, buf, sizeof(buf)));
+                               zlog_debug(
+                                       "%s [Update:SEND] %pFX is filtered by route-map",
+                                       peer->host, p);
 
                        bgp_attr_flush(attr);
                        return false;
@@ -2021,7 +2016,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
        if (aspath_check_as_zero(attr->aspath))
                return false;
 
-       if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+       if (bgp_in_graceful_shutdown(bgp)) {
                if (peer->sort == BGP_PEER_IBGP
                    || peer->sort == BGP_PEER_CONFED) {
                        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
@@ -2268,10 +2263,11 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (debug) {
                                bgp_path_info_path_with_addpath_rx_str(
                                        new_select, path_buf);
-                               zlog_debug("%s: %s is the bestpath from AS %u",
-                                          pfx_buf, path_buf,
-                                          aspath_get_first_as(
-                                                  new_select->attr->aspath));
+                               zlog_debug(
+                                       "%pBD: %s is the bestpath from AS %u",
+                                       dest, path_buf,
+                                       aspath_get_first_as(
+                                               new_select->attr->aspath));
                        }
                }
        }
@@ -2345,8 +2341,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                else
                        snprintf(path_buf, sizeof(path_buf), "NONE");
                zlog_debug(
-                       "%s: After path selection, newbest is %s oldbest was %s",
-                       pfx_buf, path_buf,
+                       "%pBD: After path selection, newbest is %s oldbest was %s",
+                       dest, path_buf,
                        old_select ? old_select->peer->host : "NONE");
        }
 
@@ -2361,8 +2357,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (pi == new_select) {
                                if (debug)
                                        zlog_debug(
-                                               "%s: %s is the bestpath, add to the multipath list",
-                                               pfx_buf, path_buf);
+                                               "%pBD: %s is the bestpath, add to the multipath list",
+                                               dest, path_buf);
                                bgp_mp_list_add(&mp_list, pi);
                                continue;
                        }
@@ -2379,8 +2375,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (!bgp_path_info_nexthop_cmp(pi, new_select)) {
                                if (debug)
                                        zlog_debug(
-                                               "%s: %s has the same nexthop as the bestpath, skip it",
-                                               pfx_buf, path_buf);
+                                               "%pBD: %s has the same nexthop as the bestpath, skip it",
+                                               dest, path_buf);
                                continue;
                        }
 
@@ -2391,8 +2387,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (paths_eq) {
                                if (debug)
                                        zlog_debug(
-                                               "%s: %s is equivalent to the bestpath, add to the multipath list",
-                                               pfx_buf, path_buf);
+                                               "%pBD: %s is equivalent to the bestpath, add to the multipath list",
+                                               dest, path_buf);
                                bgp_mp_list_add(&mp_list, pi);
                        }
                }
@@ -2601,7 +2597,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
                        debug = bgp_debug_bestpath(dest);
                if (debug)
                        zlog_debug(
-                               "%s: bgp delete in progress, ignoring event, p=%pRN",
+                               "%s: bgp delete in progress, ignoring event, p=%pBD",
                                __func__, dest);
                return;
        }
@@ -2625,7 +2621,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
 
        debug = bgp_debug_bestpath(dest);
        if (debug)
-               zlog_debug("%s: p=%pRN afi=%s, safi=%s start", __func__, dest,
+               zlog_debug("%s: p=%pBD afi=%s, safi=%s start", __func__, dest,
                           afi2str(afi), safi2str(safi));
 
        /* The best path calculation for the route is deferred if
@@ -2686,7 +2682,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
 
        if (debug)
                zlog_debug(
-                       "%s: p=%pRN afi=%s, safi=%s, old_select=%p, new_select=%p",
+                       "%s: p=%pBD afi=%s, safi=%s, old_select=%p, new_select=%p",
                        __func__, dest, afi2str(afi), safi2str(safi),
                        old_select, new_select);
 
@@ -3063,12 +3059,14 @@ static uint32_t bgp_filtered_routes_count(struct peer *peer, afi_t afi,
        bool filtered = false;
        struct bgp_dest *dest;
        struct bgp_adj_in *ain;
+       struct attr attr = {};
        struct bgp_table *table = peer->bgp->rib[afi][safi];
 
        for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
                for (ain = dest->adj_in; ain; ain = ain->next) {
                        const struct prefix *rn_p = bgp_dest_get_prefix(dest);
-                       struct attr attr = {};
+
+                       attr = *ain->attr;
 
                        if (bgp_input_filter(peer, rn_p, &attr, afi, safi)
                            == FILTER_DENY)
@@ -3165,7 +3163,8 @@ bool bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
                UNSET_FLAG(peer->af_sflags[afi][safi],
                           PEER_STATUS_PREFIX_LIMIT);
 
-       if (pcount > (pcount * peer->pmax_threshold[afi][safi] / 100)) {
+       if (pcount
+           > (peer->pmax[afi][safi] * peer->pmax_threshold[afi][safi] / 100)) {
                if (CHECK_FLAG(peer->af_sflags[afi][safi],
                               PEER_STATUS_PREFIX_THRESHOLD)
                    && !always)
@@ -3338,14 +3337,20 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
                (type == ZEBRA_ROUTE_BGP && stype == BGP_ROUTE_STATIC) ? true
                                                                       : false;
 
-       /* Only validated for unicast and multicast currently. */
-       /* Also valid for EVPN where the nexthop is an IP address. */
-       if (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN)
+       /*
+        * Only validated for unicast and multicast currently.
+        * Also valid for EVPN where the nexthop is an IP address.
+        * If we are a bgp static route being checked then there is
+        * no need to check to see if the nexthop is martian as
+        * that it should be ok.
+        */
+       if (is_bgp_static_route ||
+           (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN))
                return false;
 
        /* If NEXT_HOP is present, validate it. */
        if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
-               if ((attr->nexthop.s_addr == INADDR_ANY && !is_bgp_static_route)
+               if (attr->nexthop.s_addr == INADDR_ANY
                    || IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr))
                    || bgp_nexthop_self(bgp, afi, type, stype, attr, dest))
                        return true;
@@ -3364,8 +3369,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
                switch (attr->mp_nexthop_len) {
                case BGP_ATTR_NHLEN_IPV4:
                case BGP_ATTR_NHLEN_VPNV4:
-                       ret = ((attr->mp_nexthop_global_in.s_addr == INADDR_ANY
-                               && !is_bgp_static_route)
+                       ret = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY
                               || IPV4_CLASS_DE(
                                       ntohl(attr->mp_nexthop_global_in.s_addr))
                               || bgp_nexthop_self(bgp, afi, type, stype, attr,
@@ -3374,9 +3378,8 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
 
                case BGP_ATTR_NHLEN_IPV6_GLOBAL:
                case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
-                       ret = ((IN6_IS_ADDR_UNSPECIFIED(
+                       ret = (IN6_IS_ADDR_UNSPECIFIED(
                                        &attr->mp_nexthop_global)
-                               && !is_bgp_static_route)
                               || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global)
                               || IN6_IS_ADDR_MULTICAST(
                                       &attr->mp_nexthop_global)
@@ -3577,8 +3580,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
 
                        /* If graceful-shutdown is configured then add the GSHUT
                         * community to all paths received from eBGP peers */
-               } else if (CHECK_FLAG(peer->bgp->flags,
-                                     BGP_FLAG_GRACEFUL_SHUTDOWN))
+               } else if (bgp_in_graceful_shutdown(peer->bgp))
                        bgp_attr_add_gshut_community(&new_attr);
        }
 
@@ -3603,6 +3605,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                goto filtered;
        }
 
+       /* Update Overlay Index */
+       if (afi == AFI_L2VPN) {
+               overlay_index_update(&new_attr,
+                                    evpn == NULL ? NULL : &evpn->gw_ip);
+       }
+
        attr_new = bgp_attr_intern(&new_attr);
 
        /* If maximum prefix count is configured and current prefix
@@ -3848,12 +3856,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        }
                }
 #endif
-               /* Update Overlay Index */
-               if (afi == AFI_L2VPN) {
-                       overlay_index_update(
-                               pi->attr,
-                               evpn == NULL ? NULL : &evpn->gw_ip);
-               }
 
                /* Update bgp route dampening information.  */
                if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
@@ -5117,13 +5119,13 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
                        return;
                }
 
-               if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
+               if (bgp_in_graceful_shutdown(bgp))
                        bgp_attr_add_gshut_community(&attr_tmp);
 
                attr_new = bgp_attr_intern(&attr_tmp);
        } else {
 
-               if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
+               if (bgp_in_graceful_shutdown(bgp))
                        bgp_attr_add_gshut_community(&attr);
 
                attr_new = bgp_attr_intern(&attr);
@@ -6235,6 +6237,13 @@ static void bgp_aggregate_install(
                    && pi->sub_type == BGP_ROUTE_AGGREGATE)
                        break;
 
+       /*
+        * If we have paths with different MEDs, then don't install
+        * (or uninstall) the aggregate route.
+        */
+       if (aggregate->match_med && aggregate->med_mismatched)
+               goto uninstall_aggregate_route;
+
        if (aggregate->count > 0) {
                /*
                 * If the aggregate information has not changed
@@ -6279,6 +6288,7 @@ static void bgp_aggregate_install(
                bgp_path_info_add(dest, new);
                bgp_process(bgp, dest, afi, safi);
        } else {
+       uninstall_aggregate_route:
                for (pi = orig; pi; pi = pi->next)
                        if (pi->peer == bgp->peer_self
                            && pi->type == ZEBRA_ROUTE_BGP
@@ -6295,6 +6305,189 @@ static void bgp_aggregate_install(
        bgp_dest_unlock_node(dest);
 }
 
+/**
+ * Check if the current path has different MED than other known paths.
+ *
+ * \returns `true` if the MED matched the others else `false`.
+ */
+static bool bgp_aggregate_med_match(struct bgp_aggregate *aggregate,
+                                   struct bgp *bgp, struct bgp_path_info *pi)
+{
+       uint32_t cur_med = bgp_med_value(pi->attr, bgp);
+
+       /* This is the first route being analyzed. */
+       if (!aggregate->med_initialized) {
+               aggregate->med_initialized = true;
+               aggregate->med_mismatched = false;
+               aggregate->med_matched_value = cur_med;
+       } else {
+               /* Check if routes with different MED showed up. */
+               if (cur_med != aggregate->med_matched_value)
+                       aggregate->med_mismatched = true;
+       }
+
+       return !aggregate->med_mismatched;
+}
+
+/**
+ * Initializes and tests all routes in the aggregate address path for MED
+ * values.
+ *
+ * \returns `true` if all MEDs are the same otherwise `false`.
+ */
+static bool bgp_aggregate_test_all_med(struct bgp_aggregate *aggregate,
+                                      struct bgp *bgp, const struct prefix *p,
+                                      afi_t afi, safi_t safi)
+{
+       struct bgp_table *table = bgp->rib[afi][safi];
+       const struct prefix *dest_p;
+       struct bgp_dest *dest, *top;
+       struct bgp_path_info *pi;
+       bool med_matched = true;
+
+       aggregate->med_initialized = false;
+
+       top = bgp_node_get(table, p);
+       for (dest = bgp_node_get(table, p); dest;
+            dest = bgp_route_next_until(dest, top)) {
+               dest_p = bgp_dest_get_prefix(dest);
+               if (dest_p->prefixlen <= p->prefixlen)
+                       continue;
+
+               for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+                       if (BGP_PATH_HOLDDOWN(pi))
+                               continue;
+                       if (pi->sub_type == BGP_ROUTE_AGGREGATE)
+                               continue;
+                       if (!bgp_aggregate_med_match(aggregate, bgp, pi)) {
+                               med_matched = false;
+                               break;
+                       }
+               }
+               if (!med_matched)
+                       break;
+       }
+       bgp_dest_unlock_node(top);
+
+       return med_matched;
+}
+
+/**
+ * Toggles the route suppression status for this aggregate address
+ * configuration.
+ */
+static void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
+                                           struct bgp *bgp,
+                                           const struct prefix *p, afi_t afi,
+                                           safi_t safi, bool suppress)
+{
+       struct bgp_table *table = bgp->rib[afi][safi];
+       struct bgp_path_info_extra *pie;
+       const struct prefix *dest_p;
+       struct bgp_dest *dest, *top;
+       struct bgp_path_info *pi;
+       bool toggle_suppression;
+
+       /* We've found a different MED we must revert any suppressed routes. */
+       top = bgp_node_get(table, p);
+       for (dest = bgp_node_get(table, p); dest;
+            dest = bgp_route_next_until(dest, top)) {
+               dest_p = bgp_dest_get_prefix(dest);
+               if (dest_p->prefixlen <= p->prefixlen)
+                       continue;
+
+               toggle_suppression = false;
+               for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+                       if (BGP_PATH_HOLDDOWN(pi))
+                               continue;
+                       if (pi->sub_type == BGP_ROUTE_AGGREGATE)
+                               continue;
+
+                       /*
+                        * On installation it is possible that pi->extra is
+                        * set to NULL, otherwise it must exists.
+                        */
+                       assert(!suppress && pi->extra != NULL);
+
+                       /* We are toggling suppression back. */
+                       if (suppress) {
+                               pie = bgp_path_info_extra_get(pi);
+                               /* Suppress route if not suppressed already. */
+                               pie->suppress++;
+                               bgp_path_info_set_flag(dest, pi,
+                                                      BGP_PATH_ATTR_CHANGED);
+                               toggle_suppression = true;
+                               continue;
+                       }
+
+                       pie = pi->extra;
+                       assert(pie->suppress > 0);
+                       pie->suppress--;
+                       /* Install route if there is no more suppression. */
+                       if (pie->suppress == 0) {
+                               bgp_path_info_set_flag(dest, pi,
+                                                      BGP_PATH_ATTR_CHANGED);
+                               toggle_suppression = true;
+                       }
+               }
+
+               if (toggle_suppression)
+                       bgp_process(bgp, dest, afi, safi);
+       }
+       bgp_dest_unlock_node(top);
+}
+
+/**
+ * Aggregate address MED matching incremental test: this function is called
+ * when the initial aggregation occurred and we are only testing a single
+ * new path.
+ *
+ * In addition to testing and setting the MED validity it also installs back
+ * suppressed routes (if summary is configured).
+ *
+ * Must not be called in `bgp_aggregate_route`.
+ */
+static void bgp_aggregate_med_update(struct bgp_aggregate *aggregate,
+                                    struct bgp *bgp, const struct prefix *p,
+                                    afi_t afi, safi_t safi,
+                                    struct bgp_path_info *pi, bool is_adding)
+{
+       /* MED matching disabled. */
+       if (!aggregate->match_med)
+               return;
+
+       /* Aggregation with different MED, nothing to do. */
+       if (aggregate->med_mismatched)
+               return;
+
+       /*
+        * Test the current entry:
+        *
+        * is_adding == true: if the new entry doesn't match then we must
+        * install all suppressed routes.
+        *
+        * is_adding == false: if the entry being removed was the last
+        * unmatching entry then we can suppress all routes.
+        */
+       if (!is_adding) {
+               if (bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi)
+                   && aggregate->summary_only)
+                       bgp_aggregate_toggle_suppressed(aggregate, bgp, p, afi,
+                                                       safi, true);
+       } else
+               bgp_aggregate_med_match(aggregate, bgp, pi);
+
+       /* No mismatches, just quit. */
+       if (!aggregate->med_mismatched)
+               return;
+
+       /* Route summarization is disabled. */
+       if (!aggregate->summary_only)
+               return;
+
+       bgp_aggregate_toggle_suppressed(aggregate, bgp, p, afi, safi, false);
+}
+
 /* Update an aggregate as routes are added/removed from the BGP table */
 void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
                         safi_t safi, struct bgp_aggregate *aggregate)
@@ -6318,6 +6511,10 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
            || (bgp->peer_self == NULL))
                return;
 
+       /* Initialize and test routes for MED difference. */
+       if (aggregate->match_med)
+               bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi);
+
        /* ORIGIN attribute: If at least one route among routes that are
           aggregated has ORIGIN with the value INCOMPLETE, then the
           aggregated route must have the ORIGIN attribute with the value
@@ -6354,8 +6551,14 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
                        /*
                         * summary-only aggregate route suppress
                         * aggregated route announcements.
+                        *
+                        * MED matching:
+                        * Don't create summaries if MED didn't match
+                        * otherwise neither the specific routes and the
+                        * aggregation will be announced.
                         */
-                       if (aggregate->summary_only) {
+                       if (aggregate->summary_only
+                           && AGGREGATE_MED_VALID(aggregate)) {
                                (bgp_path_info_extra_get(pi))->suppress++;
                                bgp_path_info_set_flag(dest, pi,
                                                       BGP_PATH_ATTR_CHANGED);
@@ -6497,7 +6700,8 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
                        if (pi->sub_type == BGP_ROUTE_AGGREGATE)
                                continue;
 
-                       if (aggregate->summary_only && pi->extra) {
+                       if (aggregate->summary_only && pi->extra
+                           && AGGREGATE_MED_VALID(aggregate)) {
                                pi->extra->suppress--;
 
                                if (pi->extra->suppress == 0) {
@@ -6588,7 +6792,15 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp,
 
        aggregate->count++;
 
-       if (aggregate->summary_only)
+       /*
+        * This must be called before `summary` check to avoid
+        * "suppressing" twice.
+        */
+       if (aggregate->match_med)
+               bgp_aggregate_med_update(aggregate, bgp, aggr_p, afi, safi,
+                                        pinew, true);
+
+       if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
                (bgp_path_info_extra_get(pinew))->suppress++;
 
        switch (pinew->attr->origin) {
@@ -6685,9 +6897,8 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
        if (pi->sub_type == BGP_ROUTE_AGGREGATE)
                return;
 
-       if (aggregate->summary_only
-               && pi->extra
-               && pi->extra->suppress > 0) {
+       if (aggregate->summary_only && pi->extra && pi->extra->suppress > 0
+           && AGGREGATE_MED_VALID(aggregate)) {
                pi->extra->suppress--;
 
                if (pi->extra->suppress == 0) {
@@ -6697,6 +6908,14 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
                }
        }
 
+       /*
+        * This must be called after `summary` check to avoid
+        * "unsuppressing" twice.
+        */
+       if (aggregate->match_med)
+               bgp_aggregate_med_update(aggregate, bgp, aggr_p, afi, safi, pi,
+                                        true);
+
        if (aggregate->count > 0)
                aggregate->count--;
 
@@ -6953,7 +7172,7 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str,
 static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
                             safi_t safi, const char *rmap,
                             uint8_t summary_only, uint8_t as_set,
-                            uint8_t origin)
+                            uint8_t origin, bool match_med)
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int ret;
@@ -6995,6 +7214,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
        /* Make aggregate address structure. */
        aggregate = bgp_aggregate_new();
        aggregate->summary_only = summary_only;
+       aggregate->match_med = match_med;
 
        /* Network operators MUST NOT locally generate any new
         * announcements containing AS_SET or AS_CONFED_SET. If they have
@@ -7040,236 +7260,108 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
        return CMD_SUCCESS;
 }
 
-DEFUN (aggregate_address,
-       aggregate_address_cmd,
-       "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       "Configure BGP aggregate entries\n"
-       "Aggregate prefix\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
-{
-       int idx = 0;
-       argv_find(argv, argc, "A.B.C.D/M", &idx);
-       char *prefix = argv[idx]->arg;
-       char *rmap = NULL;
+DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
+      "[no] aggregate-address <A.B.C.D/M$prefix|A.B.C.D$addr A.B.C.D$mask> {"
+      "as-set$as_set_s"
+      "|summary-only$summary_only"
+      "|route-map WORD$rmap_name"
+      "|origin <egp|igp|incomplete>$origin_s"
+      "|matching-MED-only$match_med"
+      "}",
+      NO_STR
+      "Configure BGP aggregate entries\n"
+      "Aggregate prefix\n" "Aggregate address\n" "Aggregate mask\n"
+      "Generate AS set path information\n"
+      "Filter more specific routes from updates\n"
+      "Apply route map to aggregate network\n"
+      "Route map name\n"
+      "BGP origin code\n"
+      "Remote EGP\n"
+      "Local IGP\n"
+      "Unknown heritage\n"
+      "Only aggregate routes with matching MED\n")
+{
+       const char *prefix_s = NULL;
+       safi_t safi = bgp_node_safi(vty);
        uint8_t origin = BGP_ORIGIN_UNSPECIFIED;
-       int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET
-                                                          : AGGREGATE_AS_UNSET;
-       idx = 0;
-       int summary_only = argv_find(argv, argc, "summary-only", &idx)
-                                  ? AGGREGATE_SUMMARY_ONLY
-                                  : 0;
-
-       idx = 0;
-       argv_find(argv, argc, "WORD", &idx);
-       if (idx)
-               rmap = argv[idx]->arg;
-
-       idx = 0;
-       if (argv_find(argv, argc, "origin", &idx)) {
-               if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0)
-                       origin = BGP_ORIGIN_IGP;
-               if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0)
-                       origin = BGP_ORIGIN_EGP;
-               if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0)
-                       origin = BGP_ORIGIN_INCOMPLETE;
-       }
+       int as_set = AGGREGATE_AS_UNSET;
+       char prefix_buf[PREFIX2STR_BUFFER];
 
-       return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty), rmap,
-                                summary_only, as_set, origin);
-}
-
-DEFUN (aggregate_address_mask,
-       aggregate_address_mask_cmd,
-       "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       "Configure BGP aggregate entries\n"
-       "Aggregate address\n"
-       "Aggregate mask\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
-{
-       int idx = 0;
-       argv_find(argv, argc, "A.B.C.D", &idx);
-       char *prefix = argv[idx]->arg;
-       char *mask = argv[idx + 1]->arg;
-       bool rmap_found;
-       char *rmap = NULL;
-       uint8_t origin = BGP_ORIGIN_UNSPECIFIED;
-       int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET
-                                                          : AGGREGATE_AS_UNSET;
-       idx = 0;
-       int summary_only = argv_find(argv, argc, "summary-only", &idx)
-                                  ? AGGREGATE_SUMMARY_ONLY
-                                  : 0;
-
-       rmap_found = argv_find(argv, argc, "WORD", &idx);
-       if (rmap_found)
-               rmap = argv[idx]->arg;
-
-       char prefix_str[BUFSIZ];
-       int ret = netmask_str2prefix_str(prefix, mask, prefix_str);
-
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (addr_str) {
+               if (netmask_str2prefix_str(addr_str, mask_str, prefix_buf)
+                   == 0) {
+                       vty_out(vty, "%% Inconsistent address and mask\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               prefix_s = prefix_buf;
+       } else
+               prefix_s = prefix_str;
 
-       idx = 0;
-       if (argv_find(argv, argc, "origin", &idx)) {
-               if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0)
-                       origin = BGP_ORIGIN_IGP;
-               if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0)
+       if (origin_s) {
+               if (strcmp(origin_s, "egp") == 0)
                        origin = BGP_ORIGIN_EGP;
-               if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0)
+               else if (strcmp(origin_s, "igp") == 0)
+                       origin = BGP_ORIGIN_IGP;
+               else if (strcmp(origin_s, "incomplete") == 0)
                        origin = BGP_ORIGIN_INCOMPLETE;
        }
 
-       return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
-                                rmap, summary_only, as_set, origin);
-}
-
-DEFUN (no_aggregate_address,
-       no_aggregate_address_cmd,
-       "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       NO_STR
-       "Configure BGP aggregate entries\n"
-       "Aggregate prefix\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
+       if (as_set_s)
+               as_set = AGGREGATE_AS_SET;
+
+       /* Handle configuration removal, otherwise installation. */
+       if (no)
+               return bgp_aggregate_unset(vty, prefix_s, AFI_IP, safi);
+
+       return bgp_aggregate_set(vty, prefix_s, AFI_IP, safi, rmap_name,
+                                summary_only != NULL, as_set, origin,
+                                match_med != NULL);
+}
+
+DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
+      "[no] aggregate-address X:X::X:X/M$prefix {"
+      "as-set$as_set_s"
+      "|summary-only$summary_only"
+      "|route-map WORD$rmap_name"
+      "|origin <egp|igp|incomplete>$origin_s"
+      "|matching-MED-only$match_med"
+      "}",
+      NO_STR
+      "Configure BGP aggregate entries\n"
+      "Aggregate prefix\n"
+      "Generate AS set path information\n"
+      "Filter more specific routes from updates\n"
+      "Apply route map to aggregate network\n"
+      "Route map name\n"
+      "BGP origin code\n"
+      "Remote EGP\n"
+      "Local IGP\n"
+      "Unknown heritage\n"
+      "Only aggregate routes with matching MED\n")
 {
-       int idx = 0;
-       argv_find(argv, argc, "A.B.C.D/M", &idx);
-       char *prefix = argv[idx]->arg;
-       return bgp_aggregate_unset(vty, prefix, AFI_IP, bgp_node_safi(vty));
-}
-
-DEFUN (no_aggregate_address_mask,
-       no_aggregate_address_mask_cmd,
-       "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       NO_STR
-       "Configure BGP aggregate entries\n"
-       "Aggregate address\n"
-       "Aggregate mask\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
-{
-       int idx = 0;
-       argv_find(argv, argc, "A.B.C.D", &idx);
-       char *prefix = argv[idx]->arg;
-       char *mask = argv[idx + 1]->arg;
-
-       char prefix_str[BUFSIZ];
-       int ret = netmask_str2prefix_str(prefix, mask, prefix_str);
-
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_aggregate_unset(vty, prefix_str, AFI_IP, bgp_node_safi(vty));
-}
-
-DEFUN (ipv6_aggregate_address,
-       ipv6_aggregate_address_cmd,
-       "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       "Configure BGP aggregate entries\n"
-       "Aggregate prefix\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
-{
-       int idx = 0;
-       argv_find(argv, argc, "X:X::X:X/M", &idx);
-       char *prefix = argv[idx]->arg;
-       char *rmap = NULL;
-       bool rmap_found;
        uint8_t origin = BGP_ORIGIN_UNSPECIFIED;
-       int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET
-                                                          : AGGREGATE_AS_UNSET;
+       int as_set = AGGREGATE_AS_UNSET;
 
-       idx = 0;
-       int sum_only = argv_find(argv, argc, "summary-only", &idx)
-                              ? AGGREGATE_SUMMARY_ONLY
-                              : 0;
-
-       rmap_found = argv_find(argv, argc, "WORD", &idx);
-       if (rmap_found)
-               rmap = argv[idx]->arg;
-
-       idx = 0;
-       if (argv_find(argv, argc, "origin", &idx)) {
-               if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0)
-                       origin = BGP_ORIGIN_IGP;
-               if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0)
+       if (origin_s) {
+               if (strcmp(origin_s, "egp") == 0)
                        origin = BGP_ORIGIN_EGP;
-               if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0)
+               else if (strcmp(origin_s, "igp") == 0)
+                       origin = BGP_ORIGIN_IGP;
+               else if (strcmp(origin_s, "incomplete") == 0)
                        origin = BGP_ORIGIN_INCOMPLETE;
        }
 
-       return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap,
-                                sum_only, as_set, origin);
-}
+       if (as_set_s)
+               as_set = AGGREGATE_AS_SET;
 
-DEFUN (no_ipv6_aggregate_address,
-       no_ipv6_aggregate_address_cmd,
-       "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]",
-       NO_STR
-       "Configure BGP aggregate entries\n"
-       "Aggregate prefix\n"
-       "Generate AS set path information\n"
-       "Filter more specific routes from updates\n"
-       "Filter more specific routes from updates\n"
-       "Generate AS set path information\n"
-       "Apply route map to aggregate network\n"
-       "Name of route map\n"
-       "BGP origin code\n"
-       "Remote EGP\n"
-       "Local IGP\n"
-       "Unknown heritage\n")
-{
-       int idx = 0;
-       argv_find(argv, argc, "X:X::X:X/M", &idx);
-       char *prefix = argv[idx]->arg;
-       return bgp_aggregate_unset(vty, prefix, AFI_IP6, SAFI_UNICAST);
+       /* Handle configuration removal, otherwise installation. */
+       if (no)
+               return bgp_aggregate_unset(vty, prefix_str, AFI_IP6,
+                                          SAFI_UNICAST);
+
+       return bgp_aggregate_set(vty, prefix_str, AFI_IP6, SAFI_UNICAST,
+                                rmap_name, summary_only != NULL, as_set,
+                                origin, match_med != NULL);
 }
 
 /* Redistribute route treatment. */
@@ -7364,7 +7456,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                        }
                }
 
-               if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
+               if (bgp_in_graceful_shutdown(bgp))
                        bgp_attr_add_gshut_community(&attr_new);
 
                bn = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi,
@@ -7514,10 +7606,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty,
 
        if (p->family == AF_INET) {
                if (!json) {
-                       len = vty_out(
-                               vty, "%s/%d",
-                               inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
-                               p->prefixlen);
+                       len = vty_out(vty, "%pFX", p);
                } else {
                        json_object_string_add(json, "prefix",
                                               inet_ntop(p->family,
@@ -7529,13 +7618,12 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty,
                }
        } else if (p->family == AF_ETHERNET) {
                prefix2str(p, buf, PREFIX_STRLEN);
-               len = vty_out(vty, "%s", buf);
+               len = vty_out(vty, "%pFX", p);
        } else if (p->family == AF_EVPN) {
                if (!json)
-                       len = vty_out(
-                               vty, "%s",
-                               bgp_evpn_route2str((struct prefix_evpn *)p, buf,
-                                                  BUFSIZ));
+                       len = vty_out(vty, "%s",
+                                     prefix2str((struct prefix_evpn *)p, buf,
+                                                BUFSIZ));
                else
                        bgp_evpn_route2json((struct prefix_evpn *)p, json);
        } else if (p->family == AF_FLOWSPEC) {
@@ -7545,10 +7633,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty,
                               NLRI_STRING_FORMAT_MIN, json);
        } else {
                if (!json)
-                       len = vty_out(
-                               vty, "%s/%d",
-                               inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
-                               p->prefixlen);
+                       len = vty_out(vty, "%pFX", p);
                else {
                        json_object_string_add(json, "prefix",
                                                inet_ntop(p->family,
@@ -8889,10 +8974,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
                }
                if (safi == SAFI_EVPN) {
                        if (!json_paths) {
-                               bgp_evpn_route2str(
-                                       (struct prefix_evpn *)
-                                               bgp_dest_get_prefix(bn),
-                                       buf2, sizeof(buf2));
+                               prefix2str((struct prefix_evpn *)
+                                                  bgp_dest_get_prefix(bn),
+                                          buf2, sizeof(buf2));
                                vty_out(vty, "  Route %s", buf2);
                                if (tag_buf[0] != '\0')
                                        vty_out(vty, " VNI %s", tag_buf);
@@ -8917,11 +9001,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
                                                pdest),
                                        buf1, sizeof(buf1));
                                if (is_pi_family_evpn(parent_ri)) {
-                                       bgp_evpn_route2str(
-                                               (struct prefix_evpn *)
-                                                       bgp_dest_get_prefix(
-                                                               dest),
-                                               buf2, sizeof(buf2));
+                                       prefix2str((struct prefix_evpn *)
+                                                          bgp_dest_get_prefix(
+                                                                  dest),
+                                                  buf2, sizeof(buf2));
                                        vty_out(vty, "  Imported from %s:%s, VNI %s\n", buf1, buf2, tag_buf);
                                } else
                                        vty_out(vty, "  Imported from %s:%s\n", buf1, buf2);
@@ -9755,15 +9838,14 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
                           bool use_json);
 static int bgp_show_community(struct vty *vty, struct bgp *bgp,
                              const char *comstr, int exact, afi_t afi,
-                             safi_t safi, bool use_json);
+                             safi_t safi, uint8_t show_flags);
 
 
 static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                          struct bgp_table *table, enum bgp_show_type type,
-                         void *output_arg, bool use_json, char *rd,
-                         int is_last, unsigned long *output_cum,
-                         unsigned long *total_cum,
-                         unsigned long *json_header_depth, bool wide)
+                         void *output_arg, char *rd, int is_last,
+                         unsigned long *output_cum, unsigned long *total_cum,
+                         unsigned long *json_header_depth, uint8_t show_flags)
 {
        struct bgp_path_info *pi;
        struct bgp_dest *dest;
@@ -9774,13 +9856,23 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
        struct prefix *p;
        json_object *json_paths = NULL;
        int first = 1;
+       bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
+       bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
 
        if (output_cum && *output_cum != 0)
                header = 0;
 
        if (use_json && !*json_header_depth) {
+               if (all)
+                       *json_header_depth = 1;
+               else {
+                       vty_out(vty, "{\n");
+                       *json_header_depth = 2;
+               }
+
                vty_out(vty,
-                       "{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64",\n \"routerId\": \"%s\",\n \"defaultLocPrf\": %u,\n"
+                       " \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64",\n \"routerId\": \"%s\",\n \"defaultLocPrf\": %u,\n"
                        " \"localAS\": %u,\n \"routes\": { ",
                        bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
                        bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
@@ -9788,7 +9880,6 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                                : bgp->name,
                        table->version, inet_ntoa(bgp->router_id),
                        bgp->default_local_pref, bgp->as);
-               *json_header_depth = 2;
                if (rd) {
                        vty_out(vty, " \"routeDistinguishers\" : {");
                        ++*json_header_depth;
@@ -10021,11 +10112,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                        if (dest_p->family == AF_FLOWSPEC) {
                                char retstr[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
 
+
                                bgp_fs_nlri_get_string(
                                        (unsigned char *)
                                                dest_p->u.prefix_flowspec.ptr,
                                        dest_p->u.prefix_flowspec.prefixlen,
-                                       retstr, NLRI_STRING_FORMAT_MIN, NULL);
+                                       retstr, NLRI_STRING_FORMAT_MIN, NULL,
+                                       family2afi(dest_p->u
+                                                  .prefix_flowspec.family));
                                if (first)
                                        vty_out(vty, "\"%s/%d\": ", retstr,
                                                dest_p->u.prefix_flowspec
@@ -10066,7 +10160,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                        unsigned long i;
                        for (i = 0; i < *json_header_depth; ++i)
                                vty_out(vty, " } ");
-                       vty_out(vty, "\n");
+                       if (!all)
+                               vty_out(vty, "\n");
                }
        } else {
                if (is_last) {
@@ -10096,9 +10191,13 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
        unsigned long json_header_depth = 0;
        struct bgp_table *itable;
        bool show_msg;
+       uint8_t show_flags = 0;
 
        show_msg = (!use_json && type == bgp_show_type_normal);
 
+       if (use_json)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
        for (dest = bgp_table_top(table); dest; dest = next) {
                const struct prefix *dest_p = bgp_dest_get_prefix(dest);
 
@@ -10114,8 +10213,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
                        memcpy(&prd, dest_p, sizeof(struct prefix_rd));
                        prefix_rd2str(&prd, rd, sizeof(rd));
                        bgp_show_table(vty, bgp, safi, itable, type, output_arg,
-                                      use_json, rd, next == NULL, &output_cum,
-                                      &total_cum, &json_header_depth, false);
+                                      rd, next == NULL, &output_cum,
+                                      &total_cum, &json_header_depth,
+                                      show_flags);
                        if (next == NULL)
                                show_msg = false;
                }
@@ -10132,11 +10232,12 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
        return CMD_SUCCESS;
 }
 static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
-                   enum bgp_show_type type, void *output_arg, bool use_json,
-                   bool wide)
+                   enum bgp_show_type type, void *output_arg,
+                   uint8_t show_flags)
 {
        struct bgp_table *table;
        unsigned long json_header_depth = 0;
+       bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        if (bgp == NULL) {
                bgp = bgp_get_default();
@@ -10166,18 +10267,18 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
        else if (safi == SAFI_LABELED_UNICAST)
                safi = SAFI_UNICAST;
 
-       return bgp_show_table(vty, bgp, safi, table, type, output_arg, use_json,
-                             NULL, 1, NULL, NULL, &json_header_depth, wide);
+       return bgp_show_table(vty, bgp, safi, table, type, output_arg, NULL, 1,
+                             NULL, NULL, &json_header_depth, show_flags);
 }
 
 static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
-                                             safi_t safi, bool use_json,
-                                             bool wide)
+                                             safi_t safi, uint8_t show_flags)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
        int is_first = 1;
        bool route_output = false;
+       bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        if (use_json)
                vty_out(vty, "{\n");
@@ -10201,7 +10302,7 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
                                        : bgp->name);
                }
                bgp_show(vty, bgp, afi, safi, bgp_show_type_normal, NULL,
-                        use_json, wide);
+                        show_flags);
        }
 
        if (use_json)
@@ -10220,7 +10321,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
        struct peer *peer;
        struct listnode *node, *nnode;
        char buf1[RD_ADDRSTRLEN];
-       char buf2[INET6_ADDRSTRLEN];
        char buf3[EVPN_ROUTE_STRLEN];
        char prefix_str[BUFSIZ];
        int count = 0;
@@ -10255,9 +10355,10 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
                if (!json) {
                        vty_out(vty, "BGP routing table entry for %s%s%s\n",
                                prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
-                               : "", prd ? ":" : "",
-                               bgp_evpn_route2str((struct prefix_evpn *)p,
-                               buf3, sizeof(buf3)));
+                                   : "",
+                               prd ? ":" : "",
+                               prefix2str((struct prefix_evpn *)p, buf3,
+                                          sizeof(buf3)));
                } else {
                        json_object_string_add(json, "rd",
                                prd ? prefix_rd2str(prd, buf1, sizeof(buf1)) :
@@ -10266,15 +10367,12 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
                }
        } else {
                if (!json) {
-                       vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
+                       vty_out(vty, "BGP routing table entry for %s%s%pFX\n",
                                ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
-                                ? prefix_rd2str(prd, buf1,
-                                        sizeof(buf1))
-                                : ""),
-                               safi == SAFI_MPLS_VPN ? ":" : "",
-                               inet_ntop(p->family, &p->u.prefix, buf2,
-                                       INET6_ADDRSTRLEN),
-                               p->prefixlen);
+                                        ? prefix_rd2str(prd, buf1,
+                                                        sizeof(buf1))
+                                        : ""),
+                               safi == SAFI_MPLS_VPN ? ":" : "", p);
 
                } else
                        json_object_string_add(json, "prefix",
@@ -10662,6 +10760,10 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
        int i;
        char *str;
        int first = 0;
+       uint8_t show_flags = 0;
+
+       if (uj)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        b = buffer_new(1024);
        for (i = 0; i < argc; i++) {
@@ -10689,7 +10791,7 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
        return bgp_show(vty, bgp, afi, safi,
                        (exact ? bgp_show_type_lcommunity_exact
                               : bgp_show_type_lcommunity),
-                       lcom, uj, false);
+                       lcom, show_flags);
 }
 
 static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
@@ -10697,6 +10799,11 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
                                    safi_t safi, bool uj)
 {
        struct community_list *list;
+       uint8_t show_flags = 0;
+
+       if (uj)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
 
        list = community_list_lookup(bgp_clist, lcom, 0,
                                     LARGE_COMMUNITY_LIST_MASTER);
@@ -10709,7 +10816,7 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
        return bgp_show(vty, bgp, afi, safi,
                        (exact ? bgp_show_type_lcommunity_list_exact
                               : bgp_show_type_lcommunity_list),
-                       list, uj, false);
+                       list, show_flags);
 }
 
 DEFUN (show_ip_bgp_large_community_list,
@@ -10772,14 +10879,17 @@ DEFUN (show_ip_bgp_large_community,
        bool exact_match = 0;
        struct bgp *bgp = NULL;
        bool uj = use_json(argc, argv);
+       uint8_t show_flags = 0;
 
-        if (uj)
-                argc--;
+       if (uj) {
+               argc--;
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       }
 
-        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
-                                            &bgp, uj);
-        if (!idx)
-                return CMD_WARNING;
+       bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+                                           &bgp, uj);
+       if (!idx)
+               return CMD_WARNING;
 
        if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
                if (argv_find(argv, argc, "exact-match", &idx))
@@ -10788,7 +10898,7 @@ DEFUN (show_ip_bgp_large_community,
                                        exact_match, afi, safi, uj);
        } else
                return bgp_show(vty, bgp, afi, safi,
-                               bgp_show_type_lcommunity_all, NULL, uj, false);
+                               bgp_show_type_lcommunity_all, NULL, show_flags);
 }
 
 static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -10935,11 +11045,11 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd,
 }
 
 /* BGP route print out function without JSON */
-DEFUN(show_ip_bgp, show_ip_bgp_cmd,
+DEFPY(show_ip_bgp, show_ip_bgp_cmd,
       "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
       " [" BGP_SAFI_WITH_LABEL_CMD_STR
       "]]\
-          <dampening <parameters>\
+          <[all$all] dampening <parameters>\
            |route-map WORD\
            |prefix-list WORD\
            |filter-list WORD\
@@ -10949,6 +11059,7 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
          >",
       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
              BGP_SAFI_WITH_LABEL_HELP_STR
+      "Display the entries for all address families\n"
       "Display detailed information about dampening\n"
       "Display detail of configured dampening parameters\n"
       "Display routes matching the route-map\n"
@@ -10971,6 +11082,17 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
        int exact_match = 0;
        struct bgp *bgp = NULL;
        int idx = 0;
+       uint8_t show_flags = 0;
+
+       /* [<ipv4|ipv6> [all]] */
+       if (all) {
+               SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+               if (argv_find(argv, argc, "ipv4", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+               if (argv_find(argv, argc, "ipv6", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+       }
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, false);
@@ -10979,7 +11101,8 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
 
        if (argv_find(argv, argc, "dampening", &idx)) {
                if (argv_find(argv, argc, "parameters", &idx))
-                       return bgp_show_dampening_parameters(vty, afi, safi);
+                       return bgp_show_dampening_parameters(vty, afi, safi,
+                                                            show_flags);
        }
 
        if (argv_find(argv, argc, "prefix-list", &idx))
@@ -11015,6 +11138,7 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
 DEFPY (show_ip_bgp_json,
        show_ip_bgp_json_cmd,
        "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
+          [all$all]\
           [cidr-only\
           |dampening <flap-statistics|dampened-paths>\
           |community [AA:NN|local-AS|no-advertise|no-export\
@@ -11029,6 +11153,7 @@ DEFPY (show_ip_bgp_json,
        BGP_INSTANCE_HELP_STR
        BGP_AFI_HELP_STR
        BGP_SAFI_WITH_LABEL_HELP_STR
+       "Display the entries for all address families\n"
        "Display only routes with non-natural netmasks\n"
        "Display detailed information about dampening\n"
        "Display flap statistics of routes\n"
@@ -11059,9 +11184,29 @@ DEFPY (show_ip_bgp_json,
        struct bgp *bgp = NULL;
        int idx = 0;
        int exact_match = 0;
+       char *community = NULL;
+       bool first = true;
+       uint8_t show_flags = 0;
 
-       if (uj)
+
+       if (uj) {
                argc--;
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       }
+
+       /* [<ipv4|ipv6> [all]] */
+       if (all) {
+               SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+
+               if (argv_find(argv, argc, "ipv4", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+               if (argv_find(argv, argc, "ipv6", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+       }
+
+       if (wide)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, uj);
@@ -11069,23 +11214,17 @@ DEFPY (show_ip_bgp_json,
                return CMD_WARNING;
 
        if (argv_find(argv, argc, "cidr-only", &idx))
-               return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
-                               NULL, uj, wide);
+               sh_type = bgp_show_type_cidr_only;
 
        if (argv_find(argv, argc, "dampening", &idx)) {
                if (argv_find(argv, argc, "dampened-paths", &idx))
-                       return bgp_show(vty, bgp, afi, safi,
-                                       bgp_show_type_dampend_paths, NULL, uj,
-                                       wide);
+                       sh_type = bgp_show_type_dampend_paths;
                else if (argv_find(argv, argc, "flap-statistics", &idx))
-                       return bgp_show(vty, bgp, afi, safi,
-                                       bgp_show_type_flap_statistics, NULL, uj,
-                                       wide);
+                       sh_type = bgp_show_type_flap_statistics;
        }
 
        if (argv_find(argv, argc, "community", &idx)) {
                char *maybecomm = NULL;
-               char *community = NULL;
 
                if (idx + 1 < argc) {
                        if (argv[idx + 1]->type == VARIABLE_TKN)
@@ -11101,16 +11240,103 @@ DEFPY (show_ip_bgp_json,
                if (argv_find(argv, argc, "exact-match", &idx))
                        exact_match = 1;
 
+               if (!community)
+                       sh_type = bgp_show_type_community_all;
+       }
+
+       if (!all) {
+               /* show bgp: AFI_IP6, show ip bgp: AFI_IP */
                if (community)
                        return bgp_show_community(vty, bgp, community,
-                                                 exact_match, afi, safi, uj);
+                                                 exact_match, afi, safi,
+                                                 show_flags);
                else
-                       return (bgp_show(vty, bgp, afi, safi,
-                                        bgp_show_type_community_all, NULL, uj,
-                                        wide));
-       }
+                       return bgp_show(vty, bgp, afi, safi, sh_type, NULL,
+                                       show_flags);
+       } else {
+               /* show <ip> bgp ipv4 all: AFI_IP, show <ip> bgp ipv6 all:
+                * AFI_IP6 */
 
-       return bgp_show(vty, bgp, afi, safi, sh_type, NULL, uj, wide);
+               if (uj)
+                       vty_out(vty, "{\n");
+
+               if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+                   || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
+                       afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+                                     ? AFI_IP
+                                     : AFI_IP6;
+                       FOREACH_SAFI (safi) {
+                               if (strmatch(get_afi_safi_str(afi, safi, true),
+                                            "Unknown"))
+                                       continue;
+
+                               if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+                                       continue;
+
+                               if (uj) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               vty_out(vty, ",\n");
+                                       vty_out(vty, "\"%s\":{\n",
+                                               get_afi_safi_str(afi, safi,
+                                                                true));
+                               } else
+                                       vty_out(vty,
+                                               "\nFor address family: %s\n",
+                                               get_afi_safi_str(afi, safi,
+                                                                false));
+
+                               if (community)
+                                       bgp_show_community(vty, bgp, community,
+                                                          exact_match, afi,
+                                                          safi, show_flags);
+                               else
+                                       bgp_show(vty, bgp, afi, safi, sh_type,
+                                                NULL, show_flags);
+                               if (uj)
+                                       vty_out(vty, "}\n");
+                       }
+               } else {
+                       /* show <ip> bgp all: for each AFI and SAFI*/
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               if (strmatch(get_afi_safi_str(afi, safi, true),
+                                            "Unknown"))
+                                       continue;
+
+                               if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+                                       continue;
+
+                               if (uj) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               vty_out(vty, ",\n");
+
+                                       vty_out(vty, "\"%s\":{\n",
+                                               get_afi_safi_str(afi, safi,
+                                                                true));
+                               } else
+                                       vty_out(vty,
+                                               "\nFor address family: %s\n",
+                                               get_afi_safi_str(afi, safi,
+                                                                false));
+
+                               if (community)
+                                       bgp_show_community(vty, bgp, community,
+                                                          exact_match, afi,
+                                                          safi, show_flags);
+                               else
+                                       bgp_show(vty, bgp, afi, safi, sh_type,
+                                                NULL, show_flags);
+                               if (uj)
+                                       vty_out(vty, "}\n");
+                       }
+               }
+               if (uj)
+                       vty_out(vty, "}\n");
+       }
+       return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_bgp_route,
@@ -11237,16 +11463,22 @@ DEFPY (show_ip_bgp_instance_all,
        safi_t safi = SAFI_UNICAST;
        struct bgp *bgp = NULL;
        int idx = 0;
+       uint8_t show_flags = 0;
 
-       if (uj)
+       if (uj) {
                argc--;
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       }
+
+       if (wide)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, uj);
        if (!idx)
                return CMD_WARNING;
 
-       bgp_show_all_instances_routes_vty(vty, afi, safi, uj, wide);
+       bgp_show_all_instances_routes_vty(vty, afi, safi, show_flags);
        return CMD_SUCCESS;
 }
 
@@ -11256,6 +11488,10 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
 {
        regex_t *regex;
        int rc;
+       uint8_t show_flags = 0;
+
+       if (use_json)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        if (!config_bgp_aspath_validate(regstr)) {
                vty_out(vty, "Invalid character in REGEX %s\n",
@@ -11269,7 +11505,7 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
                return CMD_WARNING;
        }
 
-       rc = bgp_show(vty, bgp, afi, safi, type, regex, use_json, false);
+       rc = bgp_show(vty, bgp, afi, safi, type, regex, show_flags);
        bgp_regex_free(regex);
        return rc;
 }
@@ -11279,6 +11515,7 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp,
                                safi_t safi, enum bgp_show_type type)
 {
        struct prefix_list *plist;
+       uint8_t show_flags = 0;
 
        plist = prefix_list_lookup(afi, prefix_list_str);
        if (plist == NULL) {
@@ -11287,7 +11524,7 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp,
                return CMD_WARNING;
        }
 
-       return bgp_show(vty, bgp, afi, safi, type, plist, 0, false);
+       return bgp_show(vty, bgp, afi, safi, type, plist, show_flags);
 }
 
 static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
@@ -11295,6 +11532,7 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
                                enum bgp_show_type type)
 {
        struct as_list *as_list;
+       uint8_t show_flags = 0;
 
        as_list = as_list_lookup(filter);
        if (as_list == NULL) {
@@ -11303,7 +11541,7 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
                return CMD_WARNING;
        }
 
-       return bgp_show(vty, bgp, afi, safi, type, as_list, 0, false);
+       return bgp_show(vty, bgp, afi, safi, type, as_list, show_flags);
 }
 
 static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
@@ -11311,6 +11549,7 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
                              enum bgp_show_type type)
 {
        struct route_map *rmap;
+       uint8_t show_flags = 0;
 
        rmap = route_map_lookup_by_name(rmap_str);
        if (!rmap) {
@@ -11318,12 +11557,12 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
                return CMD_WARNING;
        }
 
-       return bgp_show(vty, bgp, afi, safi, type, rmap, 0, false);
+       return bgp_show(vty, bgp, afi, safi, type, rmap, show_flags);
 }
 
 static int bgp_show_community(struct vty *vty, struct bgp *bgp,
                              const char *comstr, int exact, afi_t afi,
-                             safi_t safi, bool use_json)
+                             safi_t safi, uint8_t show_flags)
 {
        struct community *com;
        int ret = 0;
@@ -11337,7 +11576,7 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp,
        ret = bgp_show(vty, bgp, afi, safi,
                       (exact ? bgp_show_type_community_exact
                              : bgp_show_type_community),
-                      com, use_json, false);
+                      com, show_flags);
        community_free(&com);
 
        return ret;
@@ -11348,6 +11587,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
                                   safi_t safi)
 {
        struct community_list *list;
+       uint8_t show_flags = 0;
 
        list = community_list_lookup(bgp_clist, com, 0, COMMUNITY_LIST_MASTER);
        if (list == NULL) {
@@ -11358,7 +11598,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
        return bgp_show(vty, bgp, afi, safi,
                        (exact ? bgp_show_type_community_list_exact
                               : bgp_show_type_community_list),
-                       list, 0, false);
+                       list, show_flags);
 }
 
 static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
@@ -11367,6 +11607,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
 {
        int ret;
        struct prefix *p;
+       uint8_t show_flags = 0;
 
        p = prefix_new();
 
@@ -11376,7 +11617,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
                return CMD_WARNING;
        }
 
-       ret = bgp_show(vty, bgp, afi, safi, type, p, 0, false);
+       ret = bgp_show(vty, bgp, afi, safi, type, p, show_flags);
        prefix_free(&p);
        return ret;
 }
@@ -12190,8 +12431,8 @@ static void show_adj_route_header(struct vty *vty, struct bgp *bgp,
 
 static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
                           safi_t safi, enum bgp_show_adj_route_type type,
-                          const char *rmap_name, bool use_json,
-                          json_object *json, bool wide)
+                          const char *rmap_name, json_object *json,
+                          uint8_t show_flags)
 {
        struct bgp_table *table;
        struct bgp_adj_in *ain;
@@ -12210,6 +12451,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
        json_object *json_ar = NULL;
        struct peer_af *paf;
        bool route_filtered;
+       bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
        if (use_json) {
                json_scode = json_object_new_object();
@@ -12418,9 +12661,10 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
 
 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, bool use_json, bool wide)
+                          const char *rmap_name, uint8_t show_flags)
 {
        json_object *json = NULL;
+       bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        if (use_json)
                json = json_object_new_object();
@@ -12455,8 +12699,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
                return CMD_WARNING;
        }
 
-       show_adj_route(vty, peer, afi, safi, type, rmap_name, use_json, json,
-                      wide);
+       show_adj_route(vty, peer, afi, safi, type, rmap_name, json, show_flags);
 
        return CMD_SUCCESS;
 }
@@ -12486,6 +12729,13 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        struct peer *peer;
        enum bgp_show_adj_route_type type = bgp_show_adj_route_bestpath;
        int idx = 0;
+       uint8_t show_flags = 0;
+
+       if (uj)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
+       if (wide)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, uj);
@@ -12500,18 +12750,20 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
        if (!peer)
                return CMD_WARNING;
 
-       return peer_adj_routes(vty, peer, afi, safi, type, rmap_name, uj, wide);
+       return peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+                              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"]] neighbors <A.B.C.D|X:X::X:X|WORD> <advertised-routes|received-routes|filtered-routes> [route-map WORD] [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 WORD] [json$uj | wide$wide]",
        SHOW_STR
        IP_STR
        BGP_STR
        BGP_INSTANCE_HELP_STR
        BGP_AFI_HELP_STR
        BGP_SAFI_WITH_LABEL_HELP_STR
+       "Display the entries for all address families\n"
        "Detailed information on TCP and BGP neighbor connections\n"
        "Neighbor to display information about\n"
        "Neighbor to display information about\n"
@@ -12532,9 +12784,25 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
        struct peer *peer;
        enum bgp_show_adj_route_type type = bgp_show_adj_route_advertised;
        int idx = 0;
+       bool first = true;
+       uint8_t show_flags = 0;
 
-       if (uj)
+       if (uj) {
                argc--;
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       }
+
+       if (all) {
+               SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+               if (argv_find(argv, argc, "ipv4", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+               if (argv_find(argv, argc, "ipv6", &idx))
+                       SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+       }
+
+       if (wide)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, uj);
@@ -12559,7 +12827,66 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
        if (argv_find(argv, argc, "route-map", &idx))
                rmap_name = argv[++idx]->arg;
 
-       return peer_adj_routes(vty, peer, afi, safi, type, rmap_name, uj, wide);
+       if (!all)
+               return peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+                                      show_flags);
+       if (uj)
+               vty_out(vty, "{\n");
+
+       if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+           || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
+               afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
+                                                                 : AFI_IP6;
+               FOREACH_SAFI (safi) {
+                       if (strmatch(get_afi_safi_str(afi, safi, true),
+                                    "Unknown"))
+                               continue;
+
+                       if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+                               continue;
+
+                       if (uj) {
+                               if (first)
+                                       first = false;
+                               else
+                                       vty_out(vty, ",\n");
+                               vty_out(vty, "\"%s\":",
+                                       get_afi_safi_str(afi, safi, true));
+                       } else
+                               vty_out(vty, "\nFor address family: %s\n",
+                                       get_afi_safi_str(afi, safi, false));
+
+                       peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+                                       show_flags);
+               }
+       } else {
+               FOREACH_AFI_SAFI (afi, safi) {
+                       if (strmatch(get_afi_safi_str(afi, safi, true),
+                                    "Unknown"))
+                               continue;
+
+                       if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+                               continue;
+
+                       if (uj) {
+                               if (first)
+                                       first = false;
+                               else
+                                       vty_out(vty, ",\n");
+                               vty_out(vty, "\"%s\":",
+                                       get_afi_safi_str(afi, safi, true));
+                       } else
+                               vty_out(vty, "\nFor address family: %s\n",
+                                       get_afi_safi_str(afi, safi, false));
+
+                       peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+                                       show_flags);
+               }
+       }
+       if (uj)
+               vty_out(vty, "}\n");
+
+       return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
@@ -12648,9 +12975,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
                                   afi_t afi, safi_t safi,
                                   enum bgp_show_type type, bool use_json)
 {
-       /* labeled-unicast routes live in the unicast table */
-       if (safi == SAFI_LABELED_UNICAST)
-               safi = SAFI_UNICAST;
+       uint8_t show_flags = 0;
+
+       if (use_json)
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 
        if (!peer || !peer->afc[afi][safi]) {
                if (use_json) {
@@ -12667,8 +12995,11 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
                return CMD_WARNING;
        }
 
-       return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json,
-                       false);
+       /* labeled-unicast routes live in the unicast table */
+       if (safi == SAFI_LABELED_UNICAST)
+               safi = SAFI_UNICAST;
+
+       return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags);
 }
 
 DEFUN (show_ip_bgp_flowspec_routes_detailed,
@@ -12688,17 +13019,20 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed,
        struct bgp *bgp = NULL;
        int idx = 0;
        bool uj = use_json(argc, argv);
+       uint8_t show_flags = 0;
 
-       if (uj)
+       if (uj) {
                argc--;
+               SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+       }
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp, uj);
        if (!idx)
                return CMD_WARNING;
 
-       return bgp_show(vty, bgp, afi, safi, bgp_show_type_detail, NULL, uj,
-                       false);
+       return bgp_show(vty, bgp, afi, safi, bgp_show_type_detail, NULL,
+                       show_flags);
 }
 
 DEFUN (show_ip_bgp_neighbor_routes,
@@ -13432,7 +13766,6 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
        const struct prefix_rd *prd;
        struct bgp_static *bgp_static;
        mpls_label_t label;
-       char buf[SU_ADDRSTRLEN];
        char rdbuf[RD_ADDRSTRLEN];
 
        /* Network configuration. */
@@ -13456,10 +13789,7 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
                        prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
                        label = decode_label(&bgp_static->label);
 
-                       vty_out(vty, "  network %s/%d rd %s",
-                               inet_ntop(p->family, &p->u.prefix, buf,
-                                         SU_ADDRSTRLEN),
-                               p->prefixlen, rdbuf);
+                       vty_out(vty, "  network %pFX rd %s", p, rdbuf);
                        if (safi == SAFI_MPLS_VPN)
                                vty_out(vty, " label %u", label);
 
@@ -13557,7 +13887,6 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
        const struct prefix *p;
        struct bgp_static *bgp_static;
        struct bgp_aggregate *bgp_aggregate;
-       char buf[SU_ADDRSTRLEN];
 
        if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) {
                bgp_config_write_network_vpn(vty, bgp, afi, safi);
@@ -13578,9 +13907,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
 
                p = bgp_dest_get_prefix(dest);
 
-               vty_out(vty, "  network %s/%d",
-                       inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                       p->prefixlen);
+               vty_out(vty, "  network %pFX", p);
 
                if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
                        vty_out(vty, " label-index %u",
@@ -13604,9 +13931,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
 
                p = bgp_dest_get_prefix(dest);
 
-               vty_out(vty, "  aggregate-address %s/%d",
-                       inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
-                       p->prefixlen);
+               vty_out(vty, "  aggregate-address %pFX", p);
 
                if (bgp_aggregate->as_set)
                        vty_out(vty, " as-set");
@@ -13621,6 +13946,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
                        vty_out(vty, " origin %s",
                                bgp_origin2str(bgp_aggregate->origin));
 
+               if (bgp_aggregate->match_med)
+                       vty_out(vty, " matching-MED-only");
+
                vty_out(vty, "\n");
        }
 }
@@ -13648,7 +13976,7 @@ void bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi,
             dest = bgp_route_next(dest)) {
                bdistance = bgp_dest_get_bgp_distance_info(dest);
                if (bdistance != NULL)
-                       vty_out(vty, "  distance %d %pRN %s\n",
+                       vty_out(vty, "  distance %d %pBD %s\n",
                                bdistance->distance, dest,
                                bdistance->access_list ? bdistance->access_list
                                                       : "");
@@ -13670,36 +13998,24 @@ void bgp_route_init(void)
        install_element(BGP_NODE, &bgp_network_cmd);
        install_element(BGP_NODE, &no_bgp_table_map_cmd);
 
-       install_element(BGP_NODE, &aggregate_address_cmd);
-       install_element(BGP_NODE, &aggregate_address_mask_cmd);
-       install_element(BGP_NODE, &no_aggregate_address_cmd);
-       install_element(BGP_NODE, &no_aggregate_address_mask_cmd);
+       install_element(BGP_NODE, &aggregate_addressv4_cmd);
 
        /* IPv4 unicast configuration.  */
        install_element(BGP_IPV4_NODE, &bgp_table_map_cmd);
        install_element(BGP_IPV4_NODE, &bgp_network_cmd);
        install_element(BGP_IPV4_NODE, &no_bgp_table_map_cmd);
 
-       install_element(BGP_IPV4_NODE, &aggregate_address_cmd);
-       install_element(BGP_IPV4_NODE, &aggregate_address_mask_cmd);
-       install_element(BGP_IPV4_NODE, &no_aggregate_address_cmd);
-       install_element(BGP_IPV4_NODE, &no_aggregate_address_mask_cmd);
+       install_element(BGP_IPV4_NODE, &aggregate_addressv4_cmd);
 
        /* IPv4 multicast configuration.  */
        install_element(BGP_IPV4M_NODE, &bgp_table_map_cmd);
        install_element(BGP_IPV4M_NODE, &bgp_network_cmd);
        install_element(BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
-       install_element(BGP_IPV4M_NODE, &aggregate_address_cmd);
-       install_element(BGP_IPV4M_NODE, &aggregate_address_mask_cmd);
-       install_element(BGP_IPV4M_NODE, &no_aggregate_address_cmd);
-       install_element(BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
+       install_element(BGP_IPV4M_NODE, &aggregate_addressv4_cmd);
 
        /* IPv4 labeled-unicast configuration.  */
        install_element(BGP_IPV4L_NODE, &bgp_network_cmd);
-       install_element(BGP_IPV4L_NODE, &aggregate_address_cmd);
-       install_element(BGP_IPV4L_NODE, &aggregate_address_mask_cmd);
-       install_element(BGP_IPV4L_NODE, &no_aggregate_address_cmd);
-       install_element(BGP_IPV4L_NODE, &no_aggregate_address_mask_cmd);
+       install_element(BGP_IPV4L_NODE, &aggregate_addressv4_cmd);
 
        install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd);
        install_element(VIEW_NODE, &show_ip_bgp_cmd);
@@ -13744,15 +14060,13 @@ void bgp_route_init(void)
        install_element(BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
        install_element(BGP_IPV6_NODE, &no_bgp_table_map_cmd);
 
-       install_element(BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
-       install_element(BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
+       install_element(BGP_IPV6_NODE, &aggregate_addressv6_cmd);
 
        install_element(BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
 
        /* IPv6 labeled unicast address family. */
        install_element(BGP_IPV6L_NODE, &ipv6_bgp_network_cmd);
-       install_element(BGP_IPV6L_NODE, &ipv6_aggregate_address_cmd);
-       install_element(BGP_IPV6L_NODE, &no_ipv6_aggregate_address_cmd);
+       install_element(BGP_IPV6L_NODE, &aggregate_addressv6_cmd);
 
        install_element(BGP_NODE, &bgp_distance_cmd);
        install_element(BGP_NODE, &no_bgp_distance_cmd);