+// SPDX-License-Identifier: GPL-2.0-or-later
/**
* bgp_updgrp.c: BGP update group structures
*
* @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>
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]);
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),
*/
key = jhash_1word(peer->local_role, key);
+ /* Neighbors configured with the AIGP attribute are put in a separate
+ * update group from other neighbors.
+ */
+ key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
+
if (peer->soo[afi][safi]) {
char *soo_str = ecommunity_str(peer->soo[afi][safi]);
(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],
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;
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;
}
}
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);
+ }
}
/*
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)));
}