]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
Merge branch 'master' of https://github.com/dwalton76/frr into bgpd-draft-ietf-grow...
[mirror_frr.git] / bgpd / bgp_route.c
index 7cdc839618aaed27fd1c497ab06274fceb6033ed..46227cec79786c20a234202b5762e7b15c658428 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <zebra.h>
+#include <math.h>
 
 #include "prefix.h"
 #include "linklist.h"
@@ -1267,6 +1268,39 @@ static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
        }
 }
 
+void bgp_attr_add_gshut_community(struct attr *attr)
+{
+       struct community *old;
+       struct community *new;
+       struct community *merge;
+       struct community *gshut;
+
+       old = attr->community;
+       gshut = community_str2com("graceful-shutdown");
+
+       if (old) {
+               merge = community_merge(community_dup(old), gshut);
+
+               if (old->refcnt== 0)
+                       community_free(old);
+
+               new = community_uniq_sort(merge);
+               community_free(merge);
+       } else {
+               new = community_dup(gshut);
+       }
+
+       community_free(gshut);
+       attr->community = new;
+       attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
+
+       /* When we add the graceful-shutdown community we must also
+        * lower the local-preference */
+       attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+       attr->local_pref = BGP_GSHUT_LOCAL_PREF;
+}
+
+
 static void subgroup_announce_reset_nhop(u_char family, struct attr *attr)
 {
        if (family == AF_INET)
@@ -1580,10 +1614,18 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
        /* Route map & unsuppress-map apply. */
        if (ROUTE_MAP_OUT_NAME(filter) || (ri->extra && ri->extra->suppress)) {
                struct bgp_info info;
+               struct bgp_info_extra dummy_info_extra;
                struct attr dummy_attr;
 
                info.peer = peer;
                info.attr = attr;
+
+               if (ri->extra) {
+                       memcpy(&dummy_info_extra, ri->extra,
+                              sizeof(struct bgp_info_extra));
+                       info.extra = &dummy_info_extra;
+               }
+
                /* don't confuse inbound and outbound setting */
                RESET_FLAG(attr->rmap_change_flags);
 
@@ -1615,6 +1657,15 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
                }
        }
 
+       if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+               if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
+                       attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+                       attr->local_pref = BGP_GSHUT_LOCAL_PREF;
+               } else {
+                       bgp_attr_add_gshut_community(attr);
+               }
+       }
+
        /* After route-map has been applied, we check to see if the nexthop to
         * be carried in the attribute (that is used for the announcement) can
         * be cleared off or not. We do this in all cases where we would be
@@ -1993,18 +2044,15 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
 
 struct bgp_process_queue {
        struct bgp *bgp;
-       struct bgp_node *rn;
-       afi_t afi;
-       safi_t safi;
+       STAILQ_HEAD(, bgp_node)pqueue;
+#define BGP_PROCESS_QUEUE_EOIU_MARKER          (1 << 0)
+       unsigned int flags;
+       unsigned int queued;
 };
 
-static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
+static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
+                                afi_t afi, safi_t safi)
 {
-       struct bgp_process_queue *pq = data;
-       struct bgp *bgp = pq->bgp;
-       struct bgp_node *rn = pq->rn;
-       afi_t afi = pq->afi;
-       safi_t safi = pq->safi;
        struct prefix *p = &rn->p;
        struct bgp_info *new_select;
        struct bgp_info *old_select;
@@ -2025,7 +2073,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                bgp->main_peers_update_hold = 0;
 
                bgp_start_routeadv(bgp);
-               return WQ_SUCCESS;
+               return;
        }
 
        /* Best path selection. */
@@ -2040,7 +2088,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
         * to do this upon changes to best path except of the label index
         * changes.
         */
-       if (safi == SAFI_UNICAST) {
+       if (bgp->allocate_mpls_labels[afi][safi]) {
                if (new_select) {
                        if (!old_select
                            || bgp_label_index_differs(new_select, old_select)
@@ -2061,8 +2109,11 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                                } else
                                        bgp_register_for_label(rn, new_select);
                        }
-               } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+               } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
                        bgp_unregister_for_label(rn);
+               }
+       } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+               bgp_unregister_for_label(rn);
        }
 
        /* If best route remains the same and this is not due to user-initiated
@@ -2078,7 +2129,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                        vnc_import_bgp_add_route(bgp, p, old_select);
                        vnc_import_bgp_exterior_add_route(bgp, p, old_select);
 #endif
-                       if (bgp_fibupd_safi(safi) && !bgp->name
+                       if (bgp_fibupd_safi(safi)
                            && !bgp_option_check(BGP_OPT_NO_FIB)
                            && new_select->type == ZEBRA_ROUTE_BGP
                            && new_select->sub_type == BGP_ROUTE_NORMAL)
@@ -2106,7 +2157,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                }
 
                UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
-               return WQ_SUCCESS;
+               return;
        }
 
        /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set
@@ -2184,21 +2235,42 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                bgp_info_reap(rn, old_select);
 
        UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
-       return WQ_SUCCESS;
+       return;
 }
 
-static void bgp_processq_del(struct work_queue *wq, void *data)
+static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
 {
-       struct bgp_process_queue *pq = data;
+       struct bgp_process_queue *pqnode = data;
+       struct bgp *bgp = pqnode->bgp;
        struct bgp_table *table;
+       struct bgp_node *rn, *nrn;
+
+       /* eoiu marker */
+       if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) {
+               bgp_process_main_one(bgp, NULL, 0, 0);
 
-       bgp_unlock(pq->bgp);
-       if (pq->rn) {
-               table = bgp_node_table(pq->rn);
-               bgp_unlock_node(pq->rn);
+               return WQ_SUCCESS;
+       }
+
+       STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) {
+               table = bgp_node_table(rn);
+
+               bgp_process_main_one(bgp, rn, table->afi, table->safi);
+
+               bgp_unlock_node(rn);
                bgp_table_unlock(table);
        }
-       XFREE(MTYPE_BGP_PROCESS_QUEUE, pq);
+
+       return WQ_SUCCESS;
+}
+
+static void bgp_processq_del(struct work_queue *wq, void *data)
+{
+       struct bgp_process_queue *pqnode = data;
+
+       bgp_unlock(pqnode->bgp);
+
+       XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode);
 }
 
 void bgp_process_queue_init(void)
@@ -2213,7 +2285,7 @@ void bgp_process_queue_init(void)
                }
        }
 
-       bm->process_main_queue->spec.workfunc = &bgp_process_main;
+       bm->process_main_queue->spec.workfunc = &bgp_process_wq;
        bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
        bm->process_main_queue->spec.max_retries = 0;
        bm->process_main_queue->spec.hold = 50;
@@ -2221,31 +2293,56 @@ void bgp_process_queue_init(void)
        bm->process_main_queue->spec.yield = 50 * 1000L;
 }
 
+static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq,
+                                                       struct bgp *bgp)
+{
+       struct bgp_process_queue *pqnode;
+
+       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue));
+
+       /* unlocked in bgp_processq_del */
+       pqnode->bgp = bgp_lock(bgp);
+       STAILQ_INIT(&pqnode->pqueue);
+
+       work_queue_add(wq, pqnode);
+
+       return pqnode;
+}
+
 void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
 {
+#define ARBITRARY_PROCESS_QLEN         10000
+       struct work_queue *wq = bm->process_main_queue;
        struct bgp_process_queue *pqnode;
 
        /* already scheduled for processing? */
        if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
                return;
 
-       if (bm->process_main_queue == NULL)
+       if (wq == NULL)
                return;
 
-       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
-                        sizeof(struct bgp_process_queue));
-       if (!pqnode)
-               return;
+       /* Add route nodes to an existing work queue item until reaching the
+          limit only if is from the same BGP view and it's not an EOIU marker */
+       if (work_queue_item_count(wq)) {
+               struct work_queue_item *item = work_queue_last_item(wq);
+               pqnode = item->data;
+
+               if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
+                   pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
+                       pqnode = bgp_process_queue_work(wq, bgp);
+       } else
+               pqnode = bgp_process_queue_work(wq, bgp);
 
-       /* all unlocked in bgp_processq_del */
+       /* all unlocked in bgp_process_wq */
        bgp_table_lock(bgp_node_table(rn));
-       pqnode->rn = bgp_lock_node(rn);
-       pqnode->bgp = bgp;
-       bgp_lock(bgp);
-       pqnode->afi = afi;
-       pqnode->safi = safi;
-       work_queue_add(bm->process_main_queue, pqnode);
+
        SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+       bgp_lock_node(rn);
+
+       STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq);
+       pqnode->queued++;
+
        return;
 }
 
@@ -2256,15 +2353,9 @@ void bgp_add_eoiu_mark(struct bgp *bgp)
        if (bm->process_main_queue == NULL)
                return;
 
-       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
-                        sizeof(struct bgp_process_queue));
-       if (!pqnode)
-               return;
+       pqnode = bgp_process_queue_work(bm->process_main_queue, bgp);
 
-       pqnode->rn = NULL;
-       pqnode->bgp = bgp;
-       bgp_lock(bgp);
-       work_queue_add(bm->process_main_queue, pqnode);
+       SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER);
 }
 
 static int bgp_maximum_prefix_restart_timer(struct thread *thread)
@@ -2288,7 +2379,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
                                int always)
 {
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
                return 0;
@@ -2680,6 +2771,22 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                goto filtered;
        }
 
+       if (peer->sort == BGP_PEER_EBGP) {
+
+               /* If we receive the graceful-shutdown community from an eBGP peer we
+                * must lower local-preference */
+               if (new_attr.community &&
+                   community_include(new_attr.community, COMMUNITY_GSHUT)) {
+                       new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+                       new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
+
+               /* If graceful-shutdown is configured then add the GSHUT community to
+                * all paths received from eBGP peers */
+               } else if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+                       bgp_attr_add_gshut_community(&new_attr);
+               }
+       }
+
        /* next hop check.  */
        if (bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) {
                reason = "martian or self next-hop;";
@@ -3999,9 +4106,18 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
                        bgp_static_withdraw(bgp, p, afi, safi);
                        return;
                }
+
+               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+                       bgp_attr_add_gshut_community(&attr_tmp);
+
                attr_new = bgp_attr_intern(&attr_tmp);
-       } else
+       } else {
+
+               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+                       bgp_attr_add_gshut_community(&attr);
+
                attr_new = bgp_attr_intern(&attr);
+       }
 
        for (ri = rn->info; ri; ri = ri->next)
                if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
@@ -4775,7 +4891,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
                        }
                        if (routermac) {
                                bgp_static->router_mac =
-                                       XCALLOC(MTYPE_ATTR, ETHER_ADDR_LEN + 1);
+                                       XCALLOC(MTYPE_ATTR, ETH_ALEN + 1);
                                prefix_str2mac(routermac,
                                               bgp_static->router_mac);
                        }
@@ -6041,8 +6157,7 @@ DEFUN (no_ipv6_aggregate_address,
 
 /* Redistribute route treatment. */
 void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
-                         const struct in_addr *nexthop,
-                         const struct in6_addr *nexthop6, unsigned int ifindex,
+                         const union g_addr *nexthop, unsigned int ifindex,
                          u_int32_t metric, u_char type, u_short instance,
                          route_tag_t tag)
 {
@@ -6058,14 +6173,17 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
 
        /* Make default attribute. */
        bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
-       if (nexthop)
-               attr.nexthop = *nexthop;
-       attr.nh_ifindex = ifindex;
-
-       if (nexthop6) {
-               attr.mp_nexthop_global = *nexthop6;
-               attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
+       if (nexthop) {
+               switch (p->family) {
+               case AF_INET:
+                       attr.nexthop = nexthop->ipv4;
+                       break;
+               case AF_INET6:
+                       attr.mp_nexthop_global = nexthop->ipv6;
+                       attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
+               }
        }
+       attr.nh_ifindex = ifindex;
 
        attr.med = metric;
        attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
@@ -6107,6 +6225,9 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                        }
                }
 
+               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+                       bgp_attr_add_gshut_community(&attr_new);
+
                bn = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi,
                                      SAFI_UNICAST, p, NULL);
 
@@ -6238,6 +6359,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty)
                } else
                        len += vty_out(vty, "/%d", p->prefixlen);
        } else if (p->family == AF_ETHERNET) {
+               prefix2str(p, buf, PREFIX_STRLEN);
+               len = vty_out(vty, "%s", buf);
+       } else if (p->family == AF_EVPN) {
 #if defined(HAVE_CUMULUS)
                len = vty_out(vty, "%s",
                              bgp_evpn_route2str((struct prefix_evpn *)p, buf,
@@ -6505,15 +6629,14 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                                                len = vty_out(
                                                        vty, "%s",
                                                        binfo->peer->conf_if);
-                                               len =
-                                                       7 - len; /* len of IPv6
-                                                                   addr + max
-                                                                   len of def
-                                                                   ifname */
+                                               len = 16 - len; /* len of IPv6
+                                                                  addr + max
+                                                                  len of def
+                                                                  ifname */
 
                                                if (len < 1)
                                                        vty_out(vty, "\n%*s",
-                                                               45, " ");
+                                                               36, " ");
                                                else
                                                        vty_out(vty, "%*s", len,
                                                                " ");
@@ -6801,7 +6924,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
        if (attr) {
                if (((p->family == AF_INET)
                     && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
-                   || (safi == SAFI_EVPN && p->family == AF_ETHERNET
+                   || (safi == SAFI_EVPN
                        && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
                    || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
                        if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
@@ -6826,7 +6949,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
                        }
                } else if (((p->family == AF_INET6)
                            && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
-                          || (safi == SAFI_EVPN && p->family == AF_ETHERNET
+                          || (safi == SAFI_EVPN
                               && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
                           || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
                        char buf_a[BUFSIZ];
@@ -7326,7 +7449,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
                /* Line2 display Next-hop, Neighbor, Router-id */
                /* Display the nexthop */
-               if ((p->family == AF_INET || p->family == AF_ETHERNET)
+               if ((p->family == AF_INET || p->family == AF_ETHERNET ||
+                    p->family == AF_EVPN)
                    && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
                        || safi == SAFI_EVPN
                        || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
@@ -7969,10 +8093,11 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
 static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
                                  const char *prefix, afi_t afi, safi_t safi,
                                  enum bgp_show_type type);
-static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
+static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
+                          const char *regstr, afi_t afi,
                           safi_t safi, enum bgp_show_type type);
-static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
-                             struct cmd_token **argv, int exact, afi_t afi,
+static int bgp_show_community(struct vty *vty, struct bgp *bgp,
+                             const char *comstr, int exact, afi_t afi,
                              safi_t safi);
 
 static int bgp_show_table(struct vty *vty, struct bgp *bgp,
@@ -8257,6 +8382,8 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
        if (bgp == NULL) {
                if (!use_json)
                        vty_out(vty, "No BGP process is configured\n");
+               else
+                       vty_out(vty, "{}\n");
                return CMD_WARNING;
        }
 
@@ -8622,6 +8749,8 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
                if (!bgp) {
                        if (!use_json)
                                vty_out(vty, "No BGP process is configured\n");
+                       else
+                               vty_out(vty, "{}\n");
                        return CMD_WARNING;
                }
        }
@@ -8783,32 +8912,28 @@ DEFUN (show_ip_bgp_large_community,
 static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
                           safi_t safi);
 
-/* BGP route print out function. */
+
+/* BGP route print out function without JSON */
 DEFUN (show_ip_bgp,
        show_ip_bgp_cmd,
        "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
-          [<\
-             cidr-only\
-             |dampening <flap-statistics|dampened-paths|parameters>\
-             |route-map WORD\
-             |prefix-list WORD\
-             |filter-list WORD\
-             |statistics\
-             |community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
-             |community-list <(1-500)|WORD> [exact-match]\
-             |A.B.C.D/M longer-prefixes\
-             |X:X::X:X/M longer-prefixes>\
-          ] [json]",
+          <dampening <parameters>\
+           |route-map WORD\
+           |prefix-list WORD\
+           |filter-list WORD\
+           |statistics\
+           |community <AA:NN|local-AS|no-advertise|no-export|graceful-shutdown> [exact-match]\
+           |community-list <(1-500)|WORD> [exact-match]\
+           |A.B.C.D/M longer-prefixes\
+           |X:X::X:X/M longer-prefixes\
+         >",
        SHOW_STR
        IP_STR
        BGP_STR
        BGP_INSTANCE_HELP_STR
        BGP_AFI_HELP_STR
        BGP_SAFI_WITH_LABEL_HELP_STR
-       "Display only routes with non-natural netmasks\n"
        "Display detailed information about dampening\n"
-       "Display flap statistics of routes\n"
-       "Display paths suppressed due to dampening\n"
        "Display detail of configured dampening parameters\n"
        "Display routes matching the route-map\n"
        "A route-map to match on\n"
@@ -8822,6 +8947,7 @@ DEFUN (show_ip_bgp,
        "Do not send outside local AS (well-known community)\n"
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n"
+       "Graceful shutdown (well-known community)\n"
        "Exact match of the communities\n"
        "Display routes matching the community-list\n"
        "community-list number\n"
@@ -8830,38 +8956,22 @@ DEFUN (show_ip_bgp,
        "IPv4 prefix\n"
        "Display route and more specific routes\n"
        "IPv6 prefix\n"
-       "Display route and more specific routes\n"
-       JSON_STR)
+       "Display route and more specific routes\n")
 {
        afi_t afi = AFI_IP6;
        safi_t safi = SAFI_UNICAST;
        int exact_match = 0;
-       enum bgp_show_type sh_type = bgp_show_type_normal;
        struct bgp *bgp = NULL;
        int idx = 0;
+       int idx_community_type = 0;
 
        bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
                                            &bgp);
        if (!idx)
                return CMD_WARNING;
 
-       int uj = use_json(argc, argv);
-       if (uj)
-               argc--;
-
-       if (argv_find(argv, argc, "cidr-only", &idx))
-               return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
-                               NULL, uj);
-
        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);
-               else if (argv_find(argv, argc, "flap-statistics", &idx))
-                       return bgp_show(vty, bgp, afi, safi,
-                                       bgp_show_type_flap_statistics, NULL,
-                                       uj);
-               else if (argv_find(argv, argc, "parameters", &idx))
+               if (argv_find(argv, argc, "parameters", &idx))
                        return bgp_show_dampening_parameters(vty, afi, safi);
        }
 
@@ -8882,18 +8992,17 @@ DEFUN (show_ip_bgp,
 
        if (argv_find(argv, argc, "community", &idx)) {
                /* show a specific community */
-               if (argv_find(argv, argc, "local-AS", &idx)
-                   || argv_find(argv, argc, "no-advertise", &idx)
-                   || argv_find(argv, argc, "no-export", &idx)) {
-                       if (argv_find(argv, argc, "exact_match", &idx))
+               if (argv_find(argv, argc, "local-AS", &idx_community_type)
+                   || argv_find(argv, argc, "no-advertise", &idx_community_type)
+                   || argv_find(argv, argc, "no-export", &idx_community_type)
+                   || argv_find(argv, argc, "graceful-shutdown", &idx_community_type)
+                   || argv_find(argv, argc, "AA:NN", &idx_community_type)) {
+
+                       if (argv_find(argv, argc, "exact-match", &idx))
                                exact_match = 1;
-                       return bgp_show_community(vty, bgp, argc, argv,
+                       return bgp_show_community(vty, bgp, argv[idx_community_type]->arg,
                                                  exact_match, afi, safi);
                }
-               /* show all communities */
-               else
-                       return bgp_show(vty, bgp, afi, safi,
-                                       bgp_show_type_community_all, NULL, uj);
        }
 
        if (argv_find(argv, argc, "community-list", &idx)) {
@@ -8910,6 +9019,66 @@ DEFUN (show_ip_bgp,
                                              safi,
                                              bgp_show_type_prefix_longer);
 
+       return CMD_WARNING;
+}
+
+/* BGP route print out function with JSON */
+DEFUN (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"]]\
+          [<\
+             cidr-only\
+             |dampening <flap-statistics|dampened-paths>\
+             |community \
+          >] [json]",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       BGP_INSTANCE_HELP_STR
+       BGP_AFI_HELP_STR
+       BGP_SAFI_WITH_LABEL_HELP_STR
+       "Display only routes with non-natural netmasks\n"
+       "Display detailed information about dampening\n"
+       "Display flap statistics of routes\n"
+       "Display paths suppressed due to dampening\n"
+       "Display routes matching the communities\n"
+       JSON_STR)
+{
+       afi_t afi = AFI_IP6;
+       safi_t safi = SAFI_UNICAST;
+       enum bgp_show_type sh_type = bgp_show_type_normal;
+       struct bgp *bgp = NULL;
+       int idx = 0;
+
+       bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+                                           &bgp);
+       if (!idx)
+               return CMD_WARNING;
+
+       int uj = use_json(argc, argv);
+       if (uj)
+               argc--;
+
+       if (argv_find(argv, argc, "cidr-only", &idx))
+               return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
+                               NULL, uj);
+
+       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);
+               else if (argv_find(argv, argc, "flap-statistics", &idx))
+                       return bgp_show(vty, bgp, afi, safi,
+                                       bgp_show_type_flap_statistics, NULL,
+                                       uj);
+       }
+
+       if (argv_find(argv, argc, "community", &idx)) {
+               /* show all communities */
+               return bgp_show(vty, bgp, afi, safi,
+                               bgp_show_type_community_all, NULL, uj);
+       }
+
        if (safi == SAFI_MPLS_VPN)
                return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal,
                                         NULL, 0, uj);
@@ -9019,7 +9188,7 @@ DEFUN (show_ip_bgp_regexp,
        idx++;
 
        char *regstr = argv_concat(argv, argc, idx);
-       int rc = bgp_show_regexp(vty, (const char *)regstr, afi, safi,
+       int rc = bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
                                 bgp_show_type_regexp);
        XFREE(MTYPE_TMP, regstr);
        return rc;
@@ -9054,7 +9223,8 @@ DEFUN (show_ip_bgp_instance_all,
        return CMD_SUCCESS;
 }
 
-static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
+static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
+                          const char *regstr, afi_t afi,
                           safi_t safi, enum bgp_show_type type)
 {
        regex_t *regex;
@@ -9066,7 +9236,7 @@ static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
                return CMD_WARNING;
        }
 
-       rc = bgp_show(vty, NULL, afi, safi, type, regex, 0);
+       rc = bgp_show(vty, bgp, afi, safi, type, regex, 0);
        bgp_regex_free(regex);
        return rc;
 }
@@ -9118,39 +9288,16 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
        return bgp_show(vty, bgp, afi, safi, type, rmap, 0);
 }
 
-static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
-                             struct cmd_token **argv, int exact, afi_t afi,
+static int bgp_show_community(struct vty *vty, struct bgp *bgp,
+                             const char *comstr, int exact, afi_t afi,
                              safi_t safi)
 {
        struct community *com;
-       struct buffer *b;
-       int i;
-       char *str;
-       int first = 0;
        int ret = 0;
 
-       b = buffer_new(1024);
-       for (i = 0; i < argc; i++) {
-               if (first)
-                       buffer_putc(b, ' ');
-               else {
-                       if (strmatch(argv[i]->text, "unicast")
-                           || strmatch(argv[i]->text, "multicast"))
-                               continue;
-                       first = 1;
-               }
-
-               buffer_putstr(b, argv[i]->arg);
-       }
-       buffer_putc(b, '\0');
-
-       str = buffer_getstr(b);
-       buffer_free(b);
-
-       com = community_str2com(str);
-       XFREE(MTYPE_TMP, str);
+       com = community_str2com(comstr);
        if (!com) {
-               vty_out(vty, "%% Community malformed: \n");
+               vty_out(vty, "%% Community malformed: %s\n", comstr);
                return CMD_WARNING;
        }
 
@@ -9295,6 +9442,7 @@ static const char *table_stats_strs[] = {
 struct bgp_table_stats {
        struct bgp_table *table;
        unsigned long long counts[BGP_STATS_MAX];
+       double total_space;
 };
 
 #if 0
@@ -9363,8 +9511,8 @@ static int bgp_table_stats_walker(struct thread *t)
                        ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
                        /* announced address space */
                        if (space)
-                               ts->counts[BGP_STATS_SPACE] +=
-                                       1 << (space - rn->p.prefixlen);
+                               ts->total_space += pow(2.0,
+                                                      space - rn->p.prefixlen);
                } else if (prn->info)
                        ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
 
@@ -9474,31 +9622,26 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
                        break;
                case BGP_STATS_SPACE:
                        vty_out(vty, "%-30s: ", table_stats_strs[i]);
-                       vty_out(vty, "%12llu\n", ts.counts[i]);
-                       if (ts.counts[BGP_STATS_MAXBITLEN] < 9)
-                               break;
-                       vty_out(vty, "%30s: ", "%% announced ");
-                       vty_out(vty, "%12.2f\n",
-                               100 * (float)ts.counts[BGP_STATS_SPACE]
-                                       / (float)((uint64_t)1UL
-                                                 << ts.counts
-                                                            [BGP_STATS_MAXBITLEN]));
-                       vty_out(vty, "%30s: ", "/8 equivalent ");
-                       vty_out(vty, "%12.2f\n",
-                               (float)ts.counts[BGP_STATS_SPACE]
-                                       / (float)(1UL
-                                                 << (ts.counts
-                                                             [BGP_STATS_MAXBITLEN]
-                                                     - 8)));
-                       if (ts.counts[BGP_STATS_MAXBITLEN] < 25)
-                               break;
-                       vty_out(vty, "%30s: ", "/24 equivalent ");
-                       vty_out(vty, "%12.2f",
-                               (float)ts.counts[BGP_STATS_SPACE]
-                                       / (float)(1UL
-                                                 << (ts.counts
-                                                             [BGP_STATS_MAXBITLEN]
-                                                     - 24)));
+                       vty_out(vty, "%12g\n", ts.total_space);
+
+                       if (afi == AFI_IP6) {
+                               vty_out(vty, "%30s: ", "/32 equivalent ");
+                               vty_out(vty, "%12g\n",
+                                       ts.total_space * pow(2.0, -128+32));
+                               vty_out(vty, "%30s: ", "/48 equivalent ");
+                               vty_out(vty, "%12g\n",
+                                       ts.total_space * pow(2.0, -128+48));
+                       } else {
+                               vty_out(vty, "%30s: ", "% announced ");
+                               vty_out(vty, "%12.2f\n",
+                                       ts.total_space * 100. * pow(2.0, -32));
+                               vty_out(vty, "%30s: ", "/8 equivalent ");
+                               vty_out(vty, "%12.2f\n",
+                                       ts.total_space * pow(2.0, -32+8));
+                               vty_out(vty, "%30s: ", "/24 equivalent ");
+                               vty_out(vty, "%12.2f\n",
+                                       ts.total_space * pow(2.0, -32+24));
+                       }
                        break;
                default:
                        vty_out(vty, "%-30s: ", table_stats_strs[i]);
@@ -10228,6 +10371,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
                                   afi_t afi, safi_t safi,
                                   enum bgp_show_type type, u_char use_json)
 {
+       /* labeled-unicast routes live in the unicast table */
+       if (safi == SAFI_LABELED_UNICAST)
+               safi = SAFI_UNICAST;
+
        if (!peer || !peer->afc[afi][safi]) {
                if (use_json) {
                        json_object *json_no = NULL;
@@ -11224,6 +11371,7 @@ void bgp_route_init(void)
        /* IPv4 labeled-unicast configuration.  */
        install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd);
        install_element(VIEW_NODE, &show_ip_bgp_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_json_cmd);
        install_element(VIEW_NODE, &show_ip_bgp_route_cmd);
        install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd);