]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_updgrp.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_updgrp.c
index 9d550fd19b826e555d3eaed8dcfcd1637e923ae1..a32cdb1ba42c1a212d1b928ece14083af1d525ce 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /**
  * bgp_updgrp.c: BGP update group structures
  *
@@ -6,22 +7,6 @@
  * @author Avneesh Sachdev <avneesh@sproute.net>
  * @author Rajesh Varadarajan <rajesh@sproute.net>
  * @author Pradosh Mohapatra <pradosh@sproute.net>
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -164,6 +149,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
        dst->change_local_as = src->change_local_as;
        dst->shared_network = src->shared_network;
        dst->local_role = src->local_role;
+       dst->as_path_loop_detection = src->as_path_loop_detection;
 
        if (src->soo[afi][safi]) {
                ecommunity_free(&dst->soo[afi][safi]);
@@ -360,6 +346,9 @@ static unsigned int updgrp_hash_key_make(const void *p)
        key = jhash_1word(peer->max_packet_size, key);
        key = jhash_1word(peer->pmax_out[afi][safi], key);
 
+       if (peer->as_path_loop_detection)
+               key = jhash_2words(peer->as, peer->as_path_loop_detection, key);
+
        if (peer->group)
                key = jhash_1word(jhash(peer->group->name,
                                        strlen(peer->group->name), SEED1),
@@ -454,12 +443,13 @@ static unsigned int updgrp_hash_key_make(const void *p)
                        (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS),
                        (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS));
                zlog_debug(
-                       "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u",
+                       "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d",
                        peer, (uint32_t)peer->addpath_type[afi][safi],
                        CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS),
                        CHECK_FLAG(peer->af_cap[afi][safi],
                                   PEER_UPDGRP_AF_CAP_FLAGS),
-                       peer->v_routeadv, peer->change_local_as);
+                       peer->v_routeadv, peer->change_local_as,
+                       peer->as_path_loop_detection);
                zlog_debug(
                        "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
                        peer, peer->max_packet_size, peer->pmax_out[afi][safi],
@@ -677,6 +667,15 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
        struct bgp_filter *filter;
        struct peer *peer = UPDGRP_PEER(updgrp);
        int match = 0;
+       json_object *json_updgrp = NULL;
+       json_object *json_subgrps = NULL;
+       json_object *json_subgrp = NULL;
+       json_object *json_time = NULL;
+       json_object *json_subgrp_time = NULL;
+       json_object *json_subgrp_event = NULL;
+       json_object *json_peers = NULL;
+       json_object *json_pkt_info = NULL;
+       time_t epoch_tbuf, tbuf;
 
        if (!ctx)
                return CMD_SUCCESS;
@@ -703,79 +702,233 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
 
        vty = ctx->vty;
 
-       vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
-       vty_out(vty, "  Created: %s", timestamp_string(updgrp->uptime));
+       if (ctx->uj) {
+               json_updgrp = json_object_new_object();
+               /* Display json o/p */
+               tbuf = monotime(NULL);
+               tbuf -= updgrp->uptime;
+               epoch_tbuf = time(NULL) - tbuf;
+               json_time = json_object_new_object();
+               json_object_int_add(json_time, "epoch", epoch_tbuf);
+               json_object_string_add(json_time, "epochString",
+                                      ctime(&epoch_tbuf));
+               json_object_object_add(json_updgrp, "groupCreateTime",
+                                      json_time);
+               json_object_string_add(json_updgrp, "afi",
+                                      afi2str(updgrp->afi));
+               json_object_string_add(json_updgrp, "safi",
+                                      safi2str(updgrp->safi));
+       } else {
+               vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
+               vty_out(vty, "  Created: %s", timestamp_string(updgrp->uptime));
+       }
+
        filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
-       if (filter->map[RMAP_OUT].name)
-               vty_out(vty, "  Outgoing route map: %s\n",
-                       filter->map[RMAP_OUT].name);
-       vty_out(vty, "  MRAI value (seconds): %d\n", updgrp->conf->v_routeadv);
-       if (updgrp->conf->change_local_as)
-               vty_out(vty, "  Local AS %u%s%s\n",
-                       updgrp->conf->change_local_as,
-                       CHECK_FLAG(updgrp->conf->flags,
-                                  PEER_FLAG_LOCAL_AS_NO_PREPEND)
-                               ? " no-prepend"
-                               : "",
-                       CHECK_FLAG(updgrp->conf->flags,
-                                  PEER_FLAG_LOCAL_AS_REPLACE_AS)
-                               ? " replace-as"
-                               : "");
+       if (filter->map[RMAP_OUT].name) {
+               if (ctx->uj)
+                       json_object_string_add(json_updgrp, "outRouteMap",
+                                              filter->map[RMAP_OUT].name);
+               else
+                       vty_out(vty, "  Outgoing route map: %s\n",
+                               filter->map[RMAP_OUT].name);
+       }
 
+       if (ctx->uj)
+               json_object_int_add(json_updgrp, "minRouteAdvInt",
+                                   updgrp->conf->v_routeadv);
+       else
+               vty_out(vty, "  MRAI value (seconds): %d\n",
+                       updgrp->conf->v_routeadv);
+
+       if (updgrp->conf->change_local_as) {
+               if (ctx->uj) {
+                       json_object_int_add(json_updgrp, "localAs",
+                                           updgrp->conf->change_local_as);
+                       json_object_boolean_add(
+                               json_updgrp, "noPrepend",
+                               CHECK_FLAG(updgrp->conf->flags,
+                                          PEER_FLAG_LOCAL_AS_NO_PREPEND));
+                       json_object_boolean_add(
+                               json_updgrp, "replaceLocalAs",
+                               CHECK_FLAG(updgrp->conf->flags,
+                                          PEER_FLAG_LOCAL_AS_REPLACE_AS));
+               } else {
+                       vty_out(vty, "  Local AS %u%s%s\n",
+                               updgrp->conf->change_local_as,
+                               CHECK_FLAG(updgrp->conf->flags,
+                                          PEER_FLAG_LOCAL_AS_NO_PREPEND)
+                                       ? " no-prepend"
+                                       : "",
+                               CHECK_FLAG(updgrp->conf->flags,
+                                          PEER_FLAG_LOCAL_AS_REPLACE_AS)
+                                       ? " replace-as"
+                                       : "");
+               }
+       }
+       if (ctx->uj)
+               json_subgrps = json_object_new_array();
        UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
                if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
                        continue;
-               vty_out(vty, "\n");
-               vty_out(vty, "  Update-subgroup %" PRIu64 ":\n", subgrp->id);
-               vty_out(vty, "    Created: %s",
-                       timestamp_string(subgrp->uptime));
+               if (ctx->uj) {
+                       json_subgrp = json_object_new_object();
+                       json_object_int_add(json_subgrp, "subGroupId",
+                                           subgrp->id);
+                       tbuf = monotime(NULL);
+                       tbuf -= subgrp->uptime;
+                       epoch_tbuf = time(NULL) - tbuf;
+                       json_subgrp_time = json_object_new_object();
+                       json_object_int_add(json_subgrp_time, "epoch",
+                                           epoch_tbuf);
+                       json_object_string_add(json_subgrp_time, "epochString",
+                                              ctime(&epoch_tbuf));
+                       json_object_object_add(json_subgrp, "groupCreateTime",
+                                              json_subgrp_time);
+               } else {
+                       vty_out(vty, "\n");
+                       vty_out(vty, "  Update-subgroup %" PRIu64 ":\n",
+                               subgrp->id);
+                       vty_out(vty, "    Created: %s",
+                               timestamp_string(subgrp->uptime));
+               }
 
                if (subgrp->split_from.update_group_id
                    || subgrp->split_from.subgroup_id) {
-                       vty_out(vty, "    Split from group id: %" PRIu64 "\n",
-                               subgrp->split_from.update_group_id);
-                       vty_out(vty,
-                               "    Split from subgroup id: %" PRIu64 "\n",
-                               subgrp->split_from.subgroup_id);
+                       if (ctx->uj) {
+                               json_object_int_add(
+                                       json_subgrp, "splitGroupId",
+                                       subgrp->split_from.update_group_id);
+                               json_object_int_add(
+                                       json_subgrp, "splitSubGroupId",
+                                       subgrp->split_from.subgroup_id);
+                       } else {
+                               vty_out(vty,
+                                       "    Split from group id: %" PRIu64
+                                       "\n",
+                                       subgrp->split_from.update_group_id);
+                               vty_out(vty,
+                                       "    Split from subgroup id: %" PRIu64
+                                       "\n",
+                                       subgrp->split_from.subgroup_id);
+                       }
                }
 
-               vty_out(vty, "    Join events: %u\n", subgrp->join_events);
-               vty_out(vty, "    Prune events: %u\n", subgrp->prune_events);
-               vty_out(vty, "    Merge events: %u\n", subgrp->merge_events);
-               vty_out(vty, "    Split events: %u\n", subgrp->split_events);
-               vty_out(vty, "    Update group switch events: %u\n",
-                       subgrp->updgrp_switch_events);
-               vty_out(vty, "    Peer refreshes combined: %u\n",
-                       subgrp->peer_refreshes_combined);
-               vty_out(vty, "    Merge checks triggered: %u\n",
-                       subgrp->merge_checks_triggered);
-               vty_out(vty, "    Coalesce Time: %u%s\n",
-                       (UPDGRP_INST(subgrp->update_group))->coalesce_time,
-                       subgrp->t_coalesce ? "(Running)" : "");
-               vty_out(vty, "    Version: %" PRIu64 "\n", subgrp->version);
-               vty_out(vty, "    Packet queue length: %d\n",
-                       bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
-               vty_out(vty, "    Total packets enqueued: %u\n",
-                       subgroup_total_packets_enqueued(subgrp));
-               vty_out(vty, "    Packet queue high watermark: %d\n",
-                       bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
-               vty_out(vty, "    Adj-out list count: %u\n", subgrp->adj_count);
-               vty_out(vty, "    Advertise list: %s\n",
-                       advertise_list_is_empty(subgrp) ? "empty"
-                                                       : "not empty");
-               vty_out(vty, "    Flags: %s\n",
-                       CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH)
-                               ? "R"
-                               : "");
-               if (peer)
-                       vty_out(vty, "    Max packet size: %d\n",
-                               peer->max_packet_size);
+               if (ctx->uj) {
+                       json_subgrp_event = json_object_new_object();
+                       json_object_int_add(json_subgrp_event, "joinEvents",
+                                           subgrp->join_events);
+                       json_object_int_add(json_subgrp_event, "pruneEvents",
+                                           subgrp->prune_events);
+                       json_object_int_add(json_subgrp_event, "mergeEvents",
+                                           subgrp->merge_events);
+                       json_object_int_add(json_subgrp_event, "splitEvents",
+                                           subgrp->split_events);
+                       json_object_int_add(json_subgrp_event, "switchEvents",
+                                           subgrp->updgrp_switch_events);
+                       json_object_int_add(json_subgrp_event,
+                                           "peerRefreshEvents",
+                                           subgrp->peer_refreshes_combined);
+                       json_object_int_add(json_subgrp_event,
+                                           "mergeCheckEvents",
+                                           subgrp->merge_checks_triggered);
+                       json_object_object_add(json_subgrp, "statistics",
+                                              json_subgrp_event);
+                       json_object_int_add(json_subgrp, "coalesceTime",
+                                           (UPDGRP_INST(subgrp->update_group))
+                                                   ->coalesce_time);
+                       json_object_int_add(json_subgrp, "version",
+                                           subgrp->version);
+                       json_pkt_info = json_object_new_object();
+                       json_object_int_add(
+                               json_pkt_info, "qeueueLen",
+                               bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
+                       json_object_int_add(
+                               json_pkt_info, "queuedTotal",
+                               subgroup_total_packets_enqueued(subgrp));
+                       json_object_int_add(
+                               json_pkt_info, "queueHwmLen",
+                               bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
+                       json_object_int_add(
+                               json_pkt_info, "totalEnqueued",
+                               subgroup_total_packets_enqueued(subgrp));
+                       json_object_object_add(json_subgrp, "packetQueueInfo",
+                                              json_pkt_info);
+                       json_object_int_add(json_subgrp, "adjListCount",
+                                           subgrp->adj_count);
+                       json_object_boolean_add(
+                               json_subgrp, "needsRefresh",
+                               CHECK_FLAG(subgrp->flags,
+                                          SUBGRP_FLAG_NEEDS_REFRESH));
+               } else {
+                       vty_out(vty, "    Join events: %u\n",
+                               subgrp->join_events);
+                       vty_out(vty, "    Prune events: %u\n",
+                               subgrp->prune_events);
+                       vty_out(vty, "    Merge events: %u\n",
+                               subgrp->merge_events);
+                       vty_out(vty, "    Split events: %u\n",
+                               subgrp->split_events);
+                       vty_out(vty, "    Update group switch events: %u\n",
+                               subgrp->updgrp_switch_events);
+                       vty_out(vty, "    Peer refreshes combined: %u\n",
+                               subgrp->peer_refreshes_combined);
+                       vty_out(vty, "    Merge checks triggered: %u\n",
+                               subgrp->merge_checks_triggered);
+                       vty_out(vty, "    Coalesce Time: %u%s\n",
+                               (UPDGRP_INST(subgrp->update_group))
+                                       ->coalesce_time,
+                               subgrp->t_coalesce ? "(Running)" : "");
+                       vty_out(vty, "    Version: %" PRIu64 "\n",
+                               subgrp->version);
+                       vty_out(vty, "    Packet queue length: %d\n",
+                               bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
+                       vty_out(vty, "    Total packets enqueued: %u\n",
+                               subgroup_total_packets_enqueued(subgrp));
+                       vty_out(vty, "    Packet queue high watermark: %d\n",
+                               bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
+                       vty_out(vty, "    Adj-out list count: %u\n",
+                               subgrp->adj_count);
+                       vty_out(vty, "    Advertise list: %s\n",
+                               advertise_list_is_empty(subgrp) ? "empty"
+                                                               : "not empty");
+                       vty_out(vty, "    Flags: %s\n",
+                               CHECK_FLAG(subgrp->flags,
+                                          SUBGRP_FLAG_NEEDS_REFRESH)
+                                       ? "R"
+                                       : "");
+                       if (peer)
+                               vty_out(vty, "    Max packet size: %d\n",
+                                       peer->max_packet_size);
+               }
                if (subgrp->peer_count > 0) {
-                       vty_out(vty, "    Peers:\n");
-                       SUBGRP_FOREACH_PEER (subgrp, paf)
-                               vty_out(vty, "      - %s\n", paf->peer->host);
+                       if (ctx->uj) {
+                               json_peers = json_object_new_array();
+                               SUBGRP_FOREACH_PEER (subgrp, paf) {
+                                       json_object *peer =
+                                               json_object_new_string(
+                                                       paf->peer->host);
+                                       json_object_array_add(json_peers, peer);
+                               }
+                               json_object_object_add(json_subgrp, "peers",
+                                                      json_peers);
+                       } else {
+                               vty_out(vty, "    Peers:\n");
+                               SUBGRP_FOREACH_PEER (subgrp, paf)
+                                       vty_out(vty, "      - %s\n",
+                                               paf->peer->host);
+                       }
                }
+
+               if (ctx->uj)
+                       json_object_array_add(json_subgrps, json_subgrp);
        }
+
+       if (ctx->uj) {
+               json_object_object_add(json_updgrp, "subGroup", json_subgrps);
+               json_object_object_addf(ctx->json_updategrps, json_updgrp,
+                                       "%" PRIu64, updgrp->id);
+       }
+
        return UPDWALK_CONTINUE;
 }
 
@@ -1708,14 +1861,34 @@ void update_bgp_group_free(struct bgp *bgp)
 }
 
 void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
-                      uint64_t subgrp_id)
+                      uint64_t subgrp_id, bool uj)
 {
        struct updwalk_context ctx;
+       json_object *json_vrf_obj = NULL;
+
        memset(&ctx, 0, sizeof(ctx));
        ctx.vty = vty;
        ctx.subgrp_id = subgrp_id;
+       ctx.uj = uj;
+
+       if (uj) {
+               ctx.json_updategrps = json_object_new_object();
+               json_vrf_obj = json_object_new_object();
+       }
 
        update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
+
+       if (uj) {
+               const char *vname;
+
+               if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+                       vname = VRF_DEFAULT_NAME;
+               else
+                       vname = bgp->name;
+               json_object_object_add(json_vrf_obj, vname,
+                                      ctx.json_updategrps);
+               vty_json(vty, json_vrf_obj);
+       }
 }
 
 /*
@@ -2048,10 +2221,18 @@ bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi)
                              PEER_CAP_ADDPATH_AF_RX_RCV));
 }
 
+bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
+                        afi_t afi, safi_t safi)
+{
+       return (bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi) ||
+               (safi == SAFI_LABELED_UNICAST &&
+                bgp_addpath_tx_path(peer->addpath_type[afi][SAFI_UNICAST],
+                                    bpi)));
+}
+
 bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
                        bool addpath_capable, afi_t afi, safi_t safi)
 {
        return (CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) ||
-               (addpath_capable &&
-                bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi)));
+               (addpath_capable && bgp_addpath_capable(bpi, peer, afi, safi)));
 }