diff options
Diffstat (limited to 'bgpd/bgp_debug.c')
-rw-r--r-- | bgpd/bgp_debug.c | 2717 |
1 files changed, 2717 insertions, 0 deletions
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c new file mode 100644 index 0000000..123a1ca --- /dev/null +++ b/bgpd/bgp_debug.c @@ -0,0 +1,2717 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP-4, BGP-4+ packet debug routine + * Copyright (C) 1996, 97, 99 Kunihiro Ishiguro + */ + +#include <zebra.h> + +#include "lib/bfd.h" +#include "lib/printfrr.h" +#include "prefix.h" +#include "linklist.h" +#include "stream.h" +#include "command.h" +#include "log.h" +#include "sockunion.h" +#include "memory.h" +#include "queue.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_lcommunity.h" +#include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_label.h" +#include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_evpn_vty.h" +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_packet.h" + +#include "bgpd/bgp_debug_clippy.c" + +unsigned long conf_bgp_debug_as4; +unsigned long conf_bgp_debug_neighbor_events; +unsigned long conf_bgp_debug_events; +unsigned long conf_bgp_debug_packet; +unsigned long conf_bgp_debug_filter; +unsigned long conf_bgp_debug_keepalive; +unsigned long conf_bgp_debug_update; +unsigned long conf_bgp_debug_bestpath; +unsigned long conf_bgp_debug_zebra; +unsigned long conf_bgp_debug_allow_martians; +unsigned long conf_bgp_debug_nht; +unsigned long conf_bgp_debug_update_groups; +unsigned long conf_bgp_debug_vpn; +unsigned long conf_bgp_debug_flowspec; +unsigned long conf_bgp_debug_labelpool; +unsigned long conf_bgp_debug_pbr; +unsigned long conf_bgp_debug_graceful_restart; +unsigned long conf_bgp_debug_evpn_mh; +unsigned long conf_bgp_debug_bfd; +unsigned long conf_bgp_debug_cond_adv; + +unsigned long term_bgp_debug_as4; +unsigned long term_bgp_debug_neighbor_events; +unsigned long term_bgp_debug_events; +unsigned long term_bgp_debug_packet; +unsigned long term_bgp_debug_filter; +unsigned long term_bgp_debug_keepalive; +unsigned long term_bgp_debug_update; +unsigned long term_bgp_debug_bestpath; +unsigned long term_bgp_debug_zebra; +unsigned long term_bgp_debug_allow_martians; +unsigned long term_bgp_debug_nht; +unsigned long term_bgp_debug_update_groups; +unsigned long term_bgp_debug_vpn; +unsigned long term_bgp_debug_flowspec; +unsigned long term_bgp_debug_labelpool; +unsigned long term_bgp_debug_pbr; +unsigned long term_bgp_debug_graceful_restart; +unsigned long term_bgp_debug_evpn_mh; +unsigned long term_bgp_debug_bfd; +unsigned long term_bgp_debug_cond_adv; + +struct list *bgp_debug_neighbor_events_peers = NULL; +struct list *bgp_debug_keepalive_peers = NULL; +struct list *bgp_debug_update_out_peers = NULL; +struct list *bgp_debug_update_in_peers = NULL; +struct list *bgp_debug_update_prefixes = NULL; +struct list *bgp_debug_bestpath_prefixes = NULL; +struct list *bgp_debug_zebra_prefixes = NULL; + +/* messages for BGP-4 status */ +const struct message bgp_status_msg[] = {{Idle, "Idle"}, + {Connect, "Connect"}, + {Active, "Active"}, + {OpenSent, "OpenSent"}, + {OpenConfirm, "OpenConfirm"}, + {Established, "Established"}, + {Clearing, "Clearing"}, + {Deleted, "Deleted"}, + {0}}; + +/* BGP message type string. */ +const char *const bgp_type_str[] = {NULL, "OPEN", "UPDATE", + "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", + "CAPABILITY"}; + +/* message for BGP-4 Notify */ +static const struct message bgp_notify_msg[] = { + {BGP_NOTIFY_HEADER_ERR, "Message Header Error"}, + {BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"}, + {BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"}, + {BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"}, + {BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"}, + {BGP_NOTIFY_CEASE, "Cease"}, + {BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"}, + {0}}; + +static const struct message bgp_notify_head_msg[] = { + {BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized"}, + {BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length"}, + {BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type"}, + {0}}; + +static const struct message bgp_notify_open_msg[] = { + {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, + {BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number"}, + {BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"}, + {BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, + {BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter"}, + {BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time"}, + {BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability"}, + {BGP_NOTIFY_OPEN_ROLE_MISMATCH, "/Role Mismatch"}, + {0}}; + +static const struct message bgp_notify_update_msg[] = { + {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, + {BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"}, + {BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"}, + {BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, + {BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error"}, + {BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error"}, + {BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute"}, + {BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute"}, + {BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error"}, + {BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field"}, + {BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH"}, + {0}}; + +static const struct message bgp_notify_cease_msg[] = { + {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, + {BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, + {BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administrative Shutdown"}, + {BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer De-configured"}, + {BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administrative Reset"}, + {BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected"}, + {BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change"}, + {BGP_NOTIFY_CEASE_COLLISION_RESOLUTION, + "/Connection Collision Resolution"}, + {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resources"}, + {BGP_NOTIFY_CEASE_HARD_RESET, "/Hard Reset"}, + {BGP_NOTIFY_CEASE_BFD_DOWN, "/BFD Down"}, + {0}}; + +static const struct message bgp_notify_route_refresh_msg[] = { + {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, + {BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN, "/Invalid Message Length"}, + {0}}; + +static const struct message bgp_notify_fsm_msg[] = { + {BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC, "/Unspecific"}, + {BGP_NOTIFY_FSM_ERR_SUBCODE_OPENSENT, + "/Receive Unexpected Message in OpenSent State"}, + {BGP_NOTIFY_FSM_ERR_SUBCODE_OPENCONFIRM, + "/Receive Unexpected Message in OpenConfirm State"}, + {BGP_NOTIFY_FSM_ERR_SUBCODE_ESTABLISHED, + "/Receive Unexpected Message in Established State"}, + {0}}; + +/* Origin strings. */ +const char *const bgp_origin_str[] = {"i", "e", "?"}; +const char *const bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; + +static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p); +/* Given a string return a pointer the corresponding peer structure */ +static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str) +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + int ret; + union sockunion su; + struct peer *peer; + + if (!bgp) { + return NULL; + } + ret = str2sockunion(peer_str, &su); + + /* 'swpX' string */ + if (ret < 0) { + peer = peer_lookup_by_conf_if(bgp, peer_str); + + if (!peer) + peer = peer_lookup_by_hostname(bgp, peer_str); + + return peer; + } else + return peer_lookup(bgp, &su); +} + +static void bgp_debug_list_free(struct list *list) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + if (list) + for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { + listnode_delete(list, filter); + prefix_free(&filter->p); + XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_FILTER, filter); + } +} + +/* + * Print the desc along with a list of peers/prefixes this debug is + * enabled for + */ +static void bgp_debug_list_print(struct vty *vty, const char *desc, + struct list *list) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + vty_out(vty, "%s", desc); + + if (list && !list_isempty(list)) { + vty_out(vty, " for"); + for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { + if (filter->host) + vty_out(vty, " %s", filter->host); + + if (filter->p && filter->p->family == AF_EVPN) + bgp_debug_print_evpn_prefix(vty, "", filter->p); + else if (filter->p) + vty_out(vty, " %pFX", filter->p); + } + } + + vty_out(vty, "\n"); +} + +/* + * Print the command to enable the debug for each peer/prefix this debug is + * enabled for + */ +static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, + struct list *list) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + int write = 0; + + if (list && !list_isempty(list)) { + for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { + if (filter->host) { + vty_out(vty, "%s %s\n", desc, filter->host); + write++; + } + + if (filter->p && filter->p->family == AF_EVPN) { + bgp_debug_print_evpn_prefix(vty, desc, + filter->p); + write++; + } else if (filter->p) { + vty_out(vty, "%s %pFX\n", desc, filter->p); + write++; + } + } + } + + if (!write) { + vty_out(vty, "%s\n", desc); + write++; + } + + return write; +} + +static void bgp_debug_list_add_entry(struct list *list, const char *host, + const struct prefix *p) +{ + struct bgp_debug_filter *filter; + + filter = XCALLOC(MTYPE_BGP_DEBUG_FILTER, + sizeof(struct bgp_debug_filter)); + + if (host) { + filter->host = XSTRDUP(MTYPE_BGP_DEBUG_STR, host); + filter->p = NULL; + } else if (p) { + filter->host = NULL; + filter->p = prefix_new(); + prefix_copy(filter->p, p); + } + + listnode_add(list, filter); +} + +static bool bgp_debug_list_remove_entry(struct list *list, const char *host, + const struct prefix *p) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { + if (host && strcmp(filter->host, host) == 0) { + listnode_delete(list, filter); + XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_FILTER, filter); + return true; + } else if (p && filter->p->prefixlen == p->prefixlen + && prefix_match(filter->p, p)) { + listnode_delete(list, filter); + prefix_free(&filter->p); + XFREE(MTYPE_BGP_DEBUG_FILTER, filter); + return true; + } + } + + return false; +} + +static bool bgp_debug_list_has_entry(struct list *list, const char *host, + const struct prefix *p) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { + if (host) { + if (strcmp(filter->host, host) == 0) { + return true; + } + } else if (p) { + if (filter->p->prefixlen == p->prefixlen + && prefix_match(filter->p, p)) { + return true; + } + } + } + + return false; +} + +bool bgp_debug_peer_updout_enabled(char *host) +{ + return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, + NULL)); +} + +/* Dump attribute. */ +bool bgp_dump_attr(struct attr *attr, char *buf, size_t size) +{ + if (!attr) + return false; + + buf[0] = '\0'; + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) + snprintfrr(buf, size, "nexthop %pI4", &attr->nexthop); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN))) + snprintf(buf + strlen(buf), size - strlen(buf), ", origin %s", + bgp_origin_str[attr->origin]); + + /* Add MP case. */ + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL + || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + snprintfrr(buf + strlen(buf), size - strlen(buf), + ", mp_nexthop %pI6", &attr->mp_nexthop_global); + + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + snprintfrr(buf + strlen(buf), size - strlen(buf), "(%pI6)", + &attr->mp_nexthop_local); + + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) + snprintfrr(buf, size, "nexthop %pI4", &attr->nexthop); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", localpref %u", attr->local_pref); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", aigp-metric %" PRIu64, + (unsigned long long)bgp_attr_get_aigp_metric(attr)); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) + snprintf(buf + strlen(buf), size - strlen(buf), ", metric %u", + attr->med); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", community %s", + community_str(bgp_attr_get_community(attr), false, + true)); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", large-community %s", + lcommunity_str(bgp_attr_get_lcommunity(attr), false, + true)); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", extcommunity %s", + ecommunity_str(bgp_attr_get_ecommunity(attr))); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", atomic-aggregate"); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) + snprintfrr(buf + strlen(buf), size - strlen(buf), + ", aggregated by %u %pI4", attr->aggregator_as, + &attr->aggregator_addr); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) + snprintfrr(buf + strlen(buf), size - strlen(buf), + ", originator %pI4", &attr->originator_id); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { + struct cluster_list *cluster; + int i; + + snprintf(buf + strlen(buf), size - strlen(buf), + ", clusterlist"); + + cluster = bgp_attr_get_cluster(attr); + for (i = 0; i < cluster->length / 4; i++) + snprintfrr(buf + strlen(buf), size - strlen(buf), + " %pI4", &cluster->list[i]); + } + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) + snprintf(buf + strlen(buf), size - strlen(buf), + ", pmsi tnltype %u", bgp_attr_get_pmsi_tnl_type(attr)); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) + snprintf(buf + strlen(buf), size - strlen(buf), ", path %s", + aspath_print(attr->aspath)); + + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))) { + if (attr->label_index != BGP_INVALID_LABEL_INDEX) + snprintf(buf + strlen(buf), size - strlen(buf), + ", label-index %u", attr->label_index); + } + + if (strlen(buf) > 1) + return true; + else + return false; +} + +const char *bgp_notify_code_str(char code) +{ + return lookup_msg(bgp_notify_msg, code, "Unrecognized Error Code"); +} + +const char *bgp_notify_subcode_str(char code, char subcode) +{ + + switch (code) { + case BGP_NOTIFY_HEADER_ERR: + return lookup_msg(bgp_notify_head_msg, subcode, + "Unrecognized Error Subcode"); + case BGP_NOTIFY_OPEN_ERR: + return lookup_msg(bgp_notify_open_msg, subcode, + "Unrecognized Error Subcode"); + case BGP_NOTIFY_UPDATE_ERR: + return lookup_msg(bgp_notify_update_msg, subcode, + "Unrecognized Error Subcode"); + case BGP_NOTIFY_HOLD_ERR: + break; + case BGP_NOTIFY_FSM_ERR: + return lookup_msg(bgp_notify_fsm_msg, subcode, + "Unrecognized Error Subcode"); + case BGP_NOTIFY_CEASE: + return lookup_msg(bgp_notify_cease_msg, subcode, + "Unrecognized Error Subcode"); + case BGP_NOTIFY_ROUTE_REFRESH_ERR: + return lookup_msg(bgp_notify_route_refresh_msg, subcode, + "Unrecognized Error Subcode"); + } + return ""; +} + +/* extract notify admin reason if correctly present */ +const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, + size_t datalen) +{ + memset(buf, 0, bufsz); + if (!data || datalen < 1) + return buf; + + uint8_t len = data[0]; + if (!len || len > datalen - 1) + return buf; + + return zlog_sanitize(buf, bufsz, data + 1, len); +} + +/* dump notify packet */ +void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, + const char *direct, bool hard_reset) +{ + const char *subcode_str; + const char *code_str; + const char *msg_str = NULL; + char msg_buf[1024]; + + if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS) + || CHECK_FLAG(peer->bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) { + code_str = bgp_notify_code_str(bgp_notify->code); + subcode_str = bgp_notify_subcode_str(bgp_notify->code, + bgp_notify->subcode); + + if (bgp_notify->code == BGP_NOTIFY_CEASE + && (bgp_notify->subcode == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN + || bgp_notify->subcode + == BGP_NOTIFY_CEASE_ADMIN_RESET)) { + msg_str = bgp_notify_admin_message( + msg_buf, sizeof(msg_buf), bgp_notify->raw_data, + bgp_notify->length); + } + + if (msg_str) { + zlog_info( + "%%NOTIFICATION%s: %s neighbor %s %d/%d (%s%s) \"%s\"", + hard_reset ? "(Hard Reset)" : "", + strcmp(direct, "received") == 0 + ? "received from" + : "sent to", + peer->host, bgp_notify->code, + bgp_notify->subcode, code_str, subcode_str, + msg_str); + } else { + msg_str = bgp_notify->data ? bgp_notify->data : ""; + zlog_info( + "%%NOTIFICATION%s: %s neighbor %s %d/%d (%s%s) %d bytes %s", + hard_reset ? "(Hard Reset)" : "", + strcmp(direct, "received") == 0 + ? "received from" + : "sent to", + peer->host, bgp_notify->code, + bgp_notify->subcode, code_str, subcode_str, + bgp_notify->length, msg_str); + } + } +} + +static void bgp_debug_clear_updgrp_update_dbg(struct bgp *bgp) +{ + if (!bgp) + bgp = bgp_get_default(); + update_group_walk(bgp, update_group_clear_update_dbg, NULL); +} + +static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p) +{ + char evpn_desc[PREFIX2STR_BUFFER + INET_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; + char buf2[ETHER_ADDR_STRLEN]; + + if (p->u.prefix_evpn.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)p)) { + snprintf( + evpn_desc, sizeof(evpn_desc), + "l2vpn evpn type macip mac %s", + prefix_mac2str(&p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2))); + } else { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? + AF_INET : AF_INET6; + snprintf( + evpn_desc, sizeof(evpn_desc), + "l2vpn evpn type macip mac %s ip %s", + prefix_mac2str(&p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2)), + inet_ntop( + family, + &p->u.prefix_evpn.macip_addr.ip.ip.addr, + buf, PREFIX2STR_BUFFER)); + } + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IMET_ROUTE) { + snprintfrr(evpn_desc, sizeof(evpn_desc), + "l2vpn evpn type multicast ip %pI4", + &p->u.prefix_evpn.imet_addr.ip.ipaddr_v4); + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? AF_INET + : AF_INET6; + snprintf(evpn_desc, sizeof(evpn_desc), + "l2vpn evpn type prefix ip %s/%d", + inet_ntop(family, + &p->u.prefix_evpn.prefix_addr.ip.ip.addr, + buf, PREFIX2STR_BUFFER), + p->u.prefix_evpn.prefix_addr.ip_prefix_length); + } + + vty_out(vty, "%s %s\n", desc, evpn_desc); +} + +static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv, + int argc, struct prefix *argv_p) +{ + struct ethaddr mac = {}; + struct ipaddr ip = {}; + int evpn_type = 0; + int mac_idx = 0; + int ip_idx = 0; + + if (bgp_evpn_cli_parse_type(&evpn_type, argv, argc) < 0) + return CMD_WARNING; + + if (evpn_type == BGP_EVPN_MAC_IP_ROUTE) { + memset(&ip, 0, sizeof(ip)); + + if (argv_find(argv, argc, "mac", &mac_idx)) + if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + + if (argv_find(argv, argc, "ip", &ip_idx)) + if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) { + vty_out(vty, "%% Malformed IP address\n"); + return CMD_WARNING; + } + + build_evpn_type2_prefix((struct prefix_evpn *)argv_p, + &mac, &ip); + } else if (evpn_type == BGP_EVPN_IMET_ROUTE) { + memset(&ip, 0, sizeof(ip)); + + if (argv_find(argv, argc, "ip", &ip_idx)) + if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) { + vty_out(vty, "%% Malformed IP address\n"); + return CMD_WARNING; + } + + build_evpn_type3_prefix((struct prefix_evpn *)argv_p, + ip.ipaddr_v4); + } else if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { + struct prefix ip_prefix; + + memset(&ip_prefix, 0, sizeof(ip_prefix)); + if (argv_find(argv, argc, "ip", &ip_idx)) { + (void)str2prefix(argv[ip_idx + 1]->arg, &ip_prefix); + apply_mask(&ip_prefix); + } + build_type5_prefix_from_ip_prefix( + (struct prefix_evpn *)argv_p, + &ip_prefix); + } + + return CMD_SUCCESS; +} + +/* Debug option setting interface. */ +unsigned long bgp_debug_option = 0; + +int debug(unsigned int option) +{ + return bgp_debug_option & option; +} + +DEFUN (debug_bgp_as4, + debug_bgp_as4_cmd, + "debug bgp as4", + DEBUG_STR + BGP_STR + "BGP AS4 actions\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(as4, AS4); + else { + TERM_DEBUG_ON(as4, AS4); + vty_out(vty, "BGP as4 debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_as4, + no_debug_bgp_as4_cmd, + "no debug bgp as4", + NO_STR + DEBUG_STR + BGP_STR + "BGP AS4 actions\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(as4, AS4); + else { + TERM_DEBUG_OFF(as4, AS4); + vty_out(vty, "BGP as4 debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_as4_segment, + debug_bgp_as4_segment_cmd, + "debug bgp as4 segment", + DEBUG_STR + BGP_STR + "BGP AS4 actions\n" + "BGP AS4 aspath segment handling\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(as4, AS4_SEGMENT); + else { + TERM_DEBUG_ON(as4, AS4_SEGMENT); + vty_out(vty, "BGP as4 segment debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_as4_segment, + no_debug_bgp_as4_segment_cmd, + "no debug bgp as4 segment", + NO_STR + DEBUG_STR + BGP_STR + "BGP AS4 actions\n" + "BGP AS4 aspath segment handling\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(as4, AS4_SEGMENT); + else { + TERM_DEBUG_OFF(as4, AS4_SEGMENT); + vty_out(vty, "BGP as4 segment debugging is off\n"); + } + return CMD_SUCCESS; +} + +/* debug bgp neighbor_events */ +DEFUN (debug_bgp_neighbor_events, + debug_bgp_neighbor_events_cmd, + "debug bgp neighbor-events", + DEBUG_STR + BGP_STR + "BGP Neighbor Events\n") +{ + bgp_debug_list_free(bgp_debug_neighbor_events_peers); + + if (vty->node == CONFIG_NODE) + DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); + else { + TERM_DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); + vty_out(vty, "BGP neighbor-events debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_neighbor_events_peer, + debug_bgp_neighbor_events_peer_cmd, + "debug bgp neighbor-events <A.B.C.D|X:X::X:X|WORD>", + DEBUG_STR + BGP_STR + "BGP Neighbor Events\n" + "BGP neighbor IP address to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_peer = 3; + const char *host = argv[idx_peer]->arg; + + if (!bgp_debug_neighbor_events_peers) + bgp_debug_neighbor_events_peers = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, host, + NULL)) { + vty_out(vty, + "BGP neighbor-events debugging is already enabled for %s\n", + host); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL); + + if (vty->node == CONFIG_NODE) + DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); + else { + TERM_DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); + vty_out(vty, "BGP neighbor-events debugging is on for %s\n", + host); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_neighbor_events, + no_debug_bgp_neighbor_events_cmd, + "no debug bgp neighbor-events", + NO_STR + DEBUG_STR + BGP_STR + "Neighbor Events\n") +{ + bgp_debug_list_free(bgp_debug_neighbor_events_peers); + + if (vty->node == CONFIG_NODE) + DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); + else { + TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); + vty_out(vty, "BGP neighbor-events debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_neighbor_events_peer, + no_debug_bgp_neighbor_events_peer_cmd, + "no debug bgp neighbor-events <A.B.C.D|X:X::X:X|WORD>", + NO_STR + DEBUG_STR + BGP_STR + "Neighbor Events\n" + "BGP neighbor IP address to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_peer = 4; + int found_peer = 0; + const char *host = argv[idx_peer]->arg; + + if (bgp_debug_neighbor_events_peers + && !list_isempty(bgp_debug_neighbor_events_peers)) { + found_peer = bgp_debug_list_remove_entry( + bgp_debug_neighbor_events_peers, host, NULL); + + if (list_isempty(bgp_debug_neighbor_events_peers)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); + else + TERM_DEBUG_OFF(neighbor_events, + NEIGHBOR_EVENTS); + } + } + + if (found_peer) + vty_out(vty, "BGP neighbor-events debugging is off for %s\n", + host); + else + vty_out(vty, + "BGP neighbor-events debugging was not enabled for %s\n", + host); + + return CMD_SUCCESS; +} + +/* debug bgp nht */ +DEFUN (debug_bgp_nht, + debug_bgp_nht_cmd, + "debug bgp nht", + DEBUG_STR + BGP_STR + "BGP nexthop tracking events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(nht, NHT); + else { + TERM_DEBUG_ON(nht, NHT); + vty_out(vty, "BGP nexthop tracking debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_nht, + no_debug_bgp_nht_cmd, + "no debug bgp nht", + NO_STR + DEBUG_STR + BGP_STR + "BGP nexthop tracking events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(nht, NHT); + else { + TERM_DEBUG_OFF(nht, NHT); + vty_out(vty, "BGP nexthop tracking debugging is off\n"); + } + return CMD_SUCCESS; +} + +/* debug bgp keepalives */ +DEFUN (debug_bgp_keepalive, + debug_bgp_keepalive_cmd, + "debug bgp keepalives", + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + bgp_debug_list_free(bgp_debug_keepalive_peers); + + if (vty->node == CONFIG_NODE) + DEBUG_ON(keepalive, KEEPALIVE); + else { + TERM_DEBUG_ON(keepalive, KEEPALIVE); + vty_out(vty, "BGP keepalives debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_keepalive_peer, + debug_bgp_keepalive_peer_cmd, + "debug bgp keepalives <A.B.C.D|X:X::X:X|WORD>", + DEBUG_STR + BGP_STR + "BGP keepalives\n" + "BGP IPv4 neighbor to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_peer = 3; + const char *host = argv[idx_peer]->arg; + + if (!bgp_debug_keepalive_peers) + bgp_debug_keepalive_peers = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL)) { + vty_out(vty, + "BGP keepalive debugging is already enabled for %s\n", + host); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL); + + if (vty->node == CONFIG_NODE) + DEBUG_ON(keepalive, KEEPALIVE); + else { + TERM_DEBUG_ON(keepalive, KEEPALIVE); + vty_out(vty, "BGP keepalives debugging is on for %s\n", host); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_keepalive, + no_debug_bgp_keepalive_cmd, + "no debug bgp keepalives", + NO_STR + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + bgp_debug_list_free(bgp_debug_keepalive_peers); + + if (vty->node == CONFIG_NODE) + DEBUG_OFF(keepalive, KEEPALIVE); + else { + TERM_DEBUG_OFF(keepalive, KEEPALIVE); + vty_out(vty, "BGP keepalives debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_keepalive_peer, + no_debug_bgp_keepalive_peer_cmd, + "no debug bgp keepalives <A.B.C.D|X:X::X:X|WORD>", + NO_STR + DEBUG_STR + BGP_STR + "BGP keepalives\n" + "BGP neighbor IP address to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_peer = 4; + int found_peer = 0; + const char *host = argv[idx_peer]->arg; + + if (bgp_debug_keepalive_peers + && !list_isempty(bgp_debug_keepalive_peers)) { + found_peer = bgp_debug_list_remove_entry( + bgp_debug_keepalive_peers, host, NULL); + + if (list_isempty(bgp_debug_keepalive_peers)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(keepalive, KEEPALIVE); + else + TERM_DEBUG_OFF(keepalive, KEEPALIVE); + } + } + + if (found_peer) + vty_out(vty, "BGP keepalives debugging is off for %s\n", host); + else + vty_out(vty, + "BGP keepalives debugging was not enabled for %s\n", + host); + + return CMD_SUCCESS; +} + +/* debug bgp bestpath */ +DEFPY (debug_bgp_bestpath_prefix, + debug_bgp_bestpath_prefix_cmd, + "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix", + DEBUG_STR + BGP_STR + "BGP bestpath\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + if (!bgp_debug_bestpath_prefixes) + bgp_debug_bestpath_prefixes = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, + prefix)) { + vty_out(vty, + "BGP bestpath debugging is already enabled for %s\n", + prefix_str); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(bestpath, BESTPATH); + } else { + TERM_DEBUG_ON(bestpath, BESTPATH); + vty_out(vty, "BGP bestpath debugging is on for %s\n", + prefix_str); + } + + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_bestpath_prefix, + no_debug_bgp_bestpath_prefix_cmd, + "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix", + NO_STR + DEBUG_STR + BGP_STR + "BGP bestpath\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + bool found_prefix = false; + + if (bgp_debug_bestpath_prefixes + && !list_isempty(bgp_debug_bestpath_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_bestpath_prefixes, NULL, prefix); + + if (list_isempty(bgp_debug_bestpath_prefixes)) { + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(bestpath, BESTPATH); + } else { + TERM_DEBUG_OFF(bestpath, BESTPATH); + vty_out(vty, + "BGP bestpath debugging (per prefix) is off\n"); + } + } + } + + if (found_prefix) + vty_out(vty, "BGP bestpath debugging is off for %s\n", + prefix_str); + else + vty_out(vty, "BGP bestpath debugging was not enabled for %s\n", + prefix_str); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_bestpath, + no_debug_bgp_bestpath_cmd, + "no debug bgp bestpath", + NO_STR + DEBUG_STR + BGP_STR + "BGP bestpath\n") +{ + bgp_debug_list_free(bgp_debug_bestpath_prefixes); + + if (vty->node == CONFIG_NODE) + DEBUG_OFF(bestpath, BESTPATH); + else { + TERM_DEBUG_OFF(bestpath, BESTPATH); + vty_out(vty, "BGP bestpath debugging is off\n"); + } + return CMD_SUCCESS; +} + +/* debug bgp updates */ +DEFUN (debug_bgp_update, + debug_bgp_update_cmd, + "debug bgp updates", + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + bgp_debug_list_free(bgp_debug_update_in_peers); + bgp_debug_list_free(bgp_debug_update_out_peers); + bgp_debug_list_free(bgp_debug_update_prefixes); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(update, UPDATE_IN); + DEBUG_ON(update, UPDATE_OUT); + } else { + TERM_DEBUG_ON(update, UPDATE_IN); + TERM_DEBUG_ON(update, UPDATE_OUT); + vty_out(vty, "BGP updates debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_update_direct, + debug_bgp_update_direct_cmd, + "debug bgp updates <in|out>", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n") +{ + int idx_in_out = 3; + + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) + bgp_debug_list_free(bgp_debug_update_in_peers); + else + bgp_debug_list_free(bgp_debug_update_out_peers); + + if (vty->node == CONFIG_NODE) { + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) + DEBUG_ON(update, UPDATE_IN); + else + DEBUG_ON(update, UPDATE_OUT); + } else { + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) { + TERM_DEBUG_ON(update, UPDATE_IN); + vty_out(vty, "BGP updates debugging is on (inbound)\n"); + } else { + TERM_DEBUG_ON(update, UPDATE_OUT); + vty_out(vty, + "BGP updates debugging is on (outbound)\n"); + } + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_update_direct_peer, + debug_bgp_update_direct_peer_cmd, + "debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n" + "BGP neighbor IP address to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_in_out = 3; + int idx_peer = 4; + const char *host = argv[idx_peer]->arg; + int inbound; + + if (!bgp_debug_update_in_peers) + bgp_debug_update_in_peers = list_new(); + + if (!bgp_debug_update_out_peers) + bgp_debug_update_out_peers = list_new(); + + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) + inbound = 1; + else + inbound = 0; + + if (inbound) { + if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, host, + NULL)) { + vty_out(vty, + "BGP inbound update debugging is already enabled for %s\n", + host); + return CMD_SUCCESS; + } + } + + else { + if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, + NULL)) { + vty_out(vty, + "BGP outbound update debugging is already enabled for %s\n", + host); + return CMD_SUCCESS; + } + } + + if (inbound) + bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL); + else { + struct peer *peer; + struct peer_af *paf; + int afidx; + + bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, + NULL); + peer = bgp_find_peer(vty, host); + + if (peer) { + for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; + afidx++) { + paf = peer->peer_af_array[afidx]; + if (paf != NULL) { + if (PAF_SUBGRP(paf)) { + UPDGRP_PEER_DBG_EN( + PAF_SUBGRP(paf) + ->update_group); + } + } + } + } + } + + if (vty->node == CONFIG_NODE) { + if (inbound) + DEBUG_ON(update, UPDATE_IN); + else + DEBUG_ON(update, UPDATE_OUT); + } else { + if (inbound) { + TERM_DEBUG_ON(update, UPDATE_IN); + vty_out(vty, + "BGP updates debugging is on (inbound) for %s\n", + argv[idx_peer]->arg); + } else { + TERM_DEBUG_ON(update, UPDATE_OUT); + vty_out(vty, + "BGP updates debugging is on (outbound) for %s\n", + argv[idx_peer]->arg); + } + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update_direct, + no_debug_bgp_update_direct_cmd, + "no debug bgp updates <in|out>", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n") +{ + int idx_in_out = 4; + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) { + bgp_debug_list_free(bgp_debug_update_in_peers); + + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_IN); + } else { + TERM_DEBUG_OFF(update, UPDATE_IN); + vty_out(vty, + "BGP updates debugging is off (inbound)\n"); + } + } else { + bgp_debug_list_free(bgp_debug_update_out_peers); + + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_OUT); + } else { + TERM_DEBUG_OFF(update, UPDATE_OUT); + vty_out(vty, + "BGP updates debugging is off (outbound)\n"); + } + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update_direct_peer, + no_debug_bgp_update_direct_peer_cmd, + "no debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n" + "BGP neighbor IP address to debug\n" + "BGP IPv6 neighbor to debug\n" + "BGP neighbor on interface to debug\n") +{ + int idx_in_out = 4; + int idx_peer = 5; + int inbound; + int found_peer = 0; + const char *host = argv[idx_peer]->arg; + + if (strncmp("i", argv[idx_in_out]->arg, 1) == 0) + inbound = 1; + else + inbound = 0; + + if (inbound && bgp_debug_update_in_peers + && !list_isempty(bgp_debug_update_in_peers)) { + found_peer = bgp_debug_list_remove_entry( + bgp_debug_update_in_peers, host, NULL); + + if (list_isempty(bgp_debug_update_in_peers)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(update, UPDATE_IN); + else { + TERM_DEBUG_OFF(update, UPDATE_IN); + vty_out(vty, + "BGP updates debugging (inbound) is off\n"); + } + } + } + + if (!inbound && bgp_debug_update_out_peers + && !list_isempty(bgp_debug_update_out_peers)) { + found_peer = bgp_debug_list_remove_entry( + bgp_debug_update_out_peers, host, NULL); + + if (list_isempty(bgp_debug_update_out_peers)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(update, UPDATE_OUT); + else { + TERM_DEBUG_OFF(update, UPDATE_OUT); + vty_out(vty, + "BGP updates debugging (outbound) is off\n"); + } + } + + struct peer *peer; + struct peer_af *paf; + int afidx; + peer = bgp_find_peer(vty, host); + + if (peer) { + for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; + afidx++) { + paf = peer->peer_af_array[afidx]; + if (paf != NULL) { + if (PAF_SUBGRP(paf)) { + UPDGRP_PEER_DBG_DIS( + PAF_SUBGRP(paf) + ->update_group); + } + } + } + } + } + + if (found_peer) + if (inbound) + vty_out(vty, + "BGP updates debugging (inbound) is off for %s\n", + host); + else + vty_out(vty, + "BGP updates debugging (outbound) is off for %s\n", + host); + else if (inbound) + vty_out(vty, + "BGP updates debugging (inbound) was not enabled for %s\n", + host); + else + vty_out(vty, + "BGP updates debugging (outbound) was not enabled for %s\n", + host); + + return CMD_SUCCESS; +} + +DEFPY (debug_bgp_update_prefix_afi_safi, + debug_bgp_update_prefix_afi_safi_cmd, + "debug bgp updates prefix l2vpn$afi evpn$safi type <<macip|2> mac <X:X:X:X:X:X|X:X:X:X:X:X/M> [ip <A.B.C.D|X:X::X:X>]|<multicast|3> ip <A.B.C.D|X:X::X:X>|<prefix|5> ip <A.B.C.D/M|X:X::X:X/M>>", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + L2VPN_HELP_STR + EVPN_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + MAC_STR MAC_STR MAC_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + EVPN_TYPE_5_HELP_STR + EVPN_TYPE_5_HELP_STR + IP_STR + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct prefix argv_p; + int ret = CMD_SUCCESS; + + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) + return ret; + + if (!bgp_debug_update_prefixes) + bgp_debug_update_prefixes = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, + &argv_p)) { + vty_out(vty, + "BGP updates debugging is already enabled for %pFX\n", + &argv_p); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_ON(update, UPDATE_PREFIX); + vty_out(vty, "BGP updates debugging is on for %pFX\n", &argv_p); + } + + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_update_prefix_afi_safi, + no_debug_bgp_update_prefix_afi_safi_cmd, + "no debug bgp updates prefix l2vpn$afi evpn$safi type <<macip|2> mac <X:X:X:X:X:X|X:X:X:X:X:X/M> [ip <A.B.C.D|X:X::X:X>]|<multicast|3> ip <A.B.C.D|X:X::X:X>|<prefix|5> ip <A.B.C.D/M|X:X::X:X/M>>", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + L2VPN_HELP_STR + EVPN_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + MAC_STR MAC_STR MAC_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + IP_STR + "IPv4 address\n" + "IPv6 address\n" + EVPN_TYPE_5_HELP_STR + EVPN_TYPE_5_HELP_STR + IP_STR + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct prefix argv_p; + bool found_prefix = false; + int ret = CMD_SUCCESS; + + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) + return ret; + + if (bgp_debug_update_prefixes + && !list_isempty(bgp_debug_update_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_update_prefixes, NULL, &argv_p); + + if (list_isempty(bgp_debug_update_prefixes)) { + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + vty_out(vty, + "BGP updates debugging (per prefix) is off\n"); + } + } + } + + if (found_prefix) + vty_out(vty, "BGP updates debugging is off for %pFX\n", + &argv_p); + else + vty_out(vty, "BGP updates debugging was not enabled for %pFX\n", + &argv_p); + + return ret; +} + + +DEFPY (debug_bgp_update_prefix, + debug_bgp_update_prefix_cmd, + "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + if (!bgp_debug_update_prefixes) + bgp_debug_update_prefixes = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) { + vty_out(vty, + "BGP updates debugging is already enabled for %s\n", + prefix_str); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_ON(update, UPDATE_PREFIX); + vty_out(vty, "BGP updates debugging is on for %s\n", + prefix_str); + } + + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_update_prefix, + no_debug_bgp_update_prefix_cmd, + "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + bool found_prefix = false; + + if (bgp_debug_update_prefixes + && !list_isempty(bgp_debug_update_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_update_prefixes, NULL, prefix); + + if (list_isempty(bgp_debug_update_prefixes)) { + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + vty_out(vty, + "BGP updates debugging (per prefix) is off\n"); + } + } + } + + if (found_prefix) + vty_out(vty, "BGP updates debugging is off for %s\n", + prefix_str); + else + vty_out(vty, "BGP updates debugging was not enabled for %s\n", + prefix_str); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update, + no_debug_bgp_update_cmd, + "no debug bgp updates", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + struct listnode *ln; + struct bgp *bgp; + + bgp_debug_list_free(bgp_debug_update_in_peers); + bgp_debug_list_free(bgp_debug_update_out_peers); + bgp_debug_list_free(bgp_debug_update_prefixes); + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, ln, bgp)) + bgp_debug_clear_updgrp_update_dbg(bgp); + + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_IN); + DEBUG_OFF(update, UPDATE_OUT); + DEBUG_OFF(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_OFF(update, UPDATE_IN); + TERM_DEBUG_OFF(update, UPDATE_OUT); + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + vty_out(vty, "BGP updates debugging is off\n"); + } + return CMD_SUCCESS; +} + +/* debug bgp zebra */ +DEFUN (debug_bgp_zebra, + debug_bgp_zebra_cmd, + "debug bgp zebra", + DEBUG_STR + BGP_STR + "BGP Zebra messages\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(zebra, ZEBRA); + else { + TERM_DEBUG_ON(zebra, ZEBRA); + vty_out(vty, "BGP zebra debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_graceful_restart, + debug_bgp_graceful_restart_cmd, + "debug bgp graceful-restart", + DEBUG_STR + BGP_STR + GR_DEBUG) +{ + if (vty->node == CONFIG_NODE) { + DEBUG_ON(graceful_restart, GRACEFUL_RESTART); + } else { + TERM_DEBUG_ON(graceful_restart, GRACEFUL_RESTART); + vty_out(vty, "BGP Graceful Restart debugging is on\n"); + } + return CMD_SUCCESS; +} + + +DEFPY (debug_bgp_zebra_prefix, + debug_bgp_zebra_prefix_cmd, + "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix", + DEBUG_STR + BGP_STR + "BGP Zebra messages\n" + "Specify a prefix to debug\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + if (!bgp_debug_zebra_prefixes) + bgp_debug_zebra_prefixes = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) { + vty_out(vty, "BGP zebra debugging is already enabled for %s\n", + prefix_str); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix); + + if (vty->node == CONFIG_NODE) + DEBUG_ON(zebra, ZEBRA); + else { + TERM_DEBUG_ON(zebra, ZEBRA); + vty_out(vty, "BGP zebra debugging is on for %s\n", prefix_str); + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_zebra, + no_debug_bgp_zebra_cmd, + "no debug bgp zebra", + NO_STR + DEBUG_STR + BGP_STR + "BGP Zebra messages\n") +{ + bgp_debug_list_free(bgp_debug_zebra_prefixes); + + if (vty->node == CONFIG_NODE) + DEBUG_OFF(zebra, ZEBRA); + else { + TERM_DEBUG_OFF(zebra, ZEBRA); + vty_out(vty, "BGP zebra debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_graceful_restart, + no_debug_bgp_graceful_restart_cmd, + "no debug bgp graceful-restart", + DEBUG_STR + BGP_STR + GR_DEBUG + NO_STR) +{ + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + } else { + TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + vty_out(vty, "BGP Graceful Restart debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_zebra_prefix, + no_debug_bgp_zebra_prefix_cmd, + "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix", + NO_STR + DEBUG_STR + BGP_STR + "BGP Zebra messages\n" + "Specify a prefix to debug\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + bool found_prefix = false; + + if (bgp_debug_zebra_prefixes + && !list_isempty(bgp_debug_zebra_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_zebra_prefixes, NULL, prefix); + + if (list_isempty(bgp_debug_zebra_prefixes)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(zebra, ZEBRA); + else { + TERM_DEBUG_OFF(zebra, ZEBRA); + vty_out(vty, "BGP zebra debugging is off\n"); + } + } + } + + if (found_prefix) + vty_out(vty, "BGP zebra debugging is off for %s\n", prefix_str); + else + vty_out(vty, "BGP zebra debugging was not enabled for %s\n", + prefix_str); + + return CMD_SUCCESS; +} + +/* debug bgp update-groups */ +DEFUN (debug_bgp_update_groups, + debug_bgp_update_groups_cmd, + "debug bgp update-groups", + DEBUG_STR + BGP_STR + "BGP update-groups\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(update_groups, UPDATE_GROUPS); + else { + TERM_DEBUG_ON(update_groups, UPDATE_GROUPS); + vty_out(vty, "BGP update-groups debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update_groups, + no_debug_bgp_update_groups_cmd, + "no debug bgp update-groups", + NO_STR + DEBUG_STR + BGP_STR + "BGP update-groups\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(update_groups, UPDATE_GROUPS); + else { + TERM_DEBUG_OFF(update_groups, UPDATE_GROUPS); + vty_out(vty, "BGP update-groups debugging is off\n"); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_vpn, + debug_bgp_vpn_cmd, + "debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>", + DEBUG_STR + BGP_STR + "VPN routes\n" + "leaked from vrf to vpn\n" + "leaked to vrf from vpn\n" + "route-map updates\n" + "labels\n") +{ + int idx = 3; + + if (argv_find(argv, argc, "leak-from-vrf", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_ON(vpn, VPN_LEAK_FROM_VRF); + else + TERM_DEBUG_ON(vpn, VPN_LEAK_FROM_VRF); + } else if (argv_find(argv, argc, "leak-to-vrf", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_ON(vpn, VPN_LEAK_TO_VRF); + else + TERM_DEBUG_ON(vpn, VPN_LEAK_TO_VRF); + } else if (argv_find(argv, argc, "rmap-event", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT); + else + TERM_DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT); + } else if (argv_find(argv, argc, "label", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_ON(vpn, VPN_LEAK_LABEL); + else + TERM_DEBUG_ON(vpn, VPN_LEAK_LABEL); + } else { + vty_out(vty, "%% unknown debug bgp vpn keyword\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (vty->node != CONFIG_NODE) + vty_out(vty, "enabled debug bgp vpn %s\n", argv[idx]->text); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_vpn, + no_debug_bgp_vpn_cmd, + "no debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>", + NO_STR + DEBUG_STR + BGP_STR + "VPN routes\n" + "leaked from vrf to vpn\n" + "leaked to vrf from vpn\n" + "route-map updates\n" + "labels\n") +{ + int idx = 4; + + if (argv_find(argv, argc, "leak-from-vrf", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF); + else + TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF); + + } else if (argv_find(argv, argc, "leak-to-vrf", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); + else + TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); + } else if (argv_find(argv, argc, "rmap-event", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT); + else + TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT); + } else if (argv_find(argv, argc, "label", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(vpn, VPN_LEAK_LABEL); + else + TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL); + } else { + vty_out(vty, "%% unknown debug bgp vpn keyword\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (vty->node != CONFIG_NODE) + vty_out(vty, "disabled debug bgp vpn %s\n", argv[idx]->text); + return CMD_SUCCESS; +} + +/* debug bgp pbr */ +DEFUN (debug_bgp_pbr, + debug_bgp_pbr_cmd, + "debug bgp pbr [error]", + DEBUG_STR + BGP_STR + "BGP policy based routing\n" + "BGP PBR error\n") +{ + int idx = 3; + + if (argv_find(argv, argc, "error", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_ON(pbr, PBR_ERROR); + else { + TERM_DEBUG_ON(pbr, PBR_ERROR); + vty_out(vty, "BGP policy based routing error is on\n"); + } + return CMD_SUCCESS; + } + if (vty->node == CONFIG_NODE) + DEBUG_ON(pbr, PBR); + else { + TERM_DEBUG_ON(pbr, PBR); + vty_out(vty, "BGP policy based routing is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_pbr, + no_debug_bgp_pbr_cmd, + "no debug bgp pbr [error]", + NO_STR + DEBUG_STR + BGP_STR + "BGP policy based routing\n" + "BGP PBR Error\n") +{ + int idx = 3; + + if (argv_find(argv, argc, "error", &idx)) { + if (vty->node == CONFIG_NODE) + DEBUG_OFF(pbr, PBR_ERROR); + else { + TERM_DEBUG_OFF(pbr, PBR_ERROR); + vty_out(vty, "BGP policy based routing error is off\n"); + } + return CMD_SUCCESS; + } + if (vty->node == CONFIG_NODE) + DEBUG_OFF(pbr, PBR); + else { + TERM_DEBUG_OFF(pbr, PBR); + vty_out(vty, "BGP policy based routing is off\n"); + } + return CMD_SUCCESS; +} + +DEFPY (debug_bgp_evpn_mh, + debug_bgp_evpn_mh_cmd, + "[no$no] debug bgp evpn mh <es$es|route$rt>", + NO_STR + DEBUG_STR + BGP_STR + "EVPN\n" + "Multihoming\n" + "Ethernet Segment debugging\n" + "Route debugging\n") +{ + if (es) { + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(evpn_mh, EVPN_MH_ES); + else + DEBUG_ON(evpn_mh, EVPN_MH_ES); + } else { + if (no) { + TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES); + vty_out(vty, + "BGP EVPN-MH ES debugging is off\n"); + } else { + TERM_DEBUG_ON(evpn_mh, EVPN_MH_ES); + vty_out(vty, + "BGP EVPN-MH ES debugging is on\n"); + } + } + } + if (rt) { + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(evpn_mh, EVPN_MH_RT); + else + DEBUG_ON(evpn_mh, EVPN_MH_RT); + } else { + if (no) { + TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT); + vty_out(vty, + "BGP EVPN-MH route debugging is off\n"); + } else { + TERM_DEBUG_ON(evpn_mh, EVPN_MH_RT); + vty_out(vty, + "BGP EVPN-MH route debugging is on\n"); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_labelpool, + debug_bgp_labelpool_cmd, + "debug bgp labelpool", + DEBUG_STR + BGP_STR + "label pool\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(labelpool, LABELPOOL); + else + TERM_DEBUG_ON(labelpool, LABELPOOL); + + if (vty->node != CONFIG_NODE) + vty_out(vty, "enabled debug bgp labelpool\n"); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_labelpool, + no_debug_bgp_labelpool_cmd, + "no debug bgp labelpool", + NO_STR + DEBUG_STR + BGP_STR + "label pool\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(labelpool, LABELPOOL); + else + TERM_DEBUG_OFF(labelpool, LABELPOOL); + + + if (vty->node != CONFIG_NODE) + vty_out(vty, "disabled debug bgp labelpool\n"); + + return CMD_SUCCESS; +} + +DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd, + "[no] debug bgp bfd", + NO_STR + DEBUG_STR + BGP_STR + "Bidirection Forwarding Detection\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) { + DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + } else { + DEBUG_ON(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(true); + } + } else { + if (no) { + TERM_DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + } else { + TERM_DEBUG_ON(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(true); + } + } + + return CMD_SUCCESS; +} + +DEFPY (debug_bgp_cond_adv, + debug_bgp_cond_adv_cmd, + "[no$no] debug bgp conditional-advertisement", + NO_STR + DEBUG_STR + BGP_STR + "BGP conditional advertisement\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(cond_adv, COND_ADV); + else + DEBUG_ON(cond_adv, COND_ADV); + } else { + if (no) { + TERM_DEBUG_OFF(cond_adv, COND_ADV); + vty_out(vty, + "BGP conditional advertisement debugging is off\n"); + } else { + TERM_DEBUG_ON(cond_adv, COND_ADV); + vty_out(vty, + "BGP conditional advertisement debugging is on\n"); + } + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp, + no_debug_bgp_cmd, + "no debug bgp", + NO_STR + DEBUG_STR + BGP_STR) +{ + struct bgp *bgp; + struct listnode *ln; + + bgp_debug_list_free(bgp_debug_neighbor_events_peers); + bgp_debug_list_free(bgp_debug_keepalive_peers); + bgp_debug_list_free(bgp_debug_update_in_peers); + bgp_debug_list_free(bgp_debug_update_out_peers); + bgp_debug_list_free(bgp_debug_update_prefixes); + bgp_debug_list_free(bgp_debug_bestpath_prefixes); + bgp_debug_list_free(bgp_debug_zebra_prefixes); + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, ln, bgp)) + bgp_debug_clear_updgrp_update_dbg(bgp); + + TERM_DEBUG_OFF(keepalive, KEEPALIVE); + TERM_DEBUG_OFF(update, UPDATE_IN); + TERM_DEBUG_OFF(update, UPDATE_OUT); + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + TERM_DEBUG_OFF(bestpath, BESTPATH); + TERM_DEBUG_OFF(as4, AS4); + TERM_DEBUG_OFF(as4, AS4_SEGMENT); + TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); + TERM_DEBUG_OFF(zebra, ZEBRA); + TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS); + TERM_DEBUG_OFF(nht, NHT); + TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF); + TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); + TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT); + TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL); + TERM_DEBUG_OFF(flowspec, FLOWSPEC); + TERM_DEBUG_OFF(labelpool, LABELPOOL); + TERM_DEBUG_OFF(pbr, PBR); + TERM_DEBUG_OFF(pbr, PBR_ERROR); + TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); + TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES); + TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT); + TERM_DEBUG_OFF(bfd, BFD_LIB); + TERM_DEBUG_OFF(cond_adv, COND_ADV); + + vty_out(vty, "All possible debugging has been turned off\n"); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (show_debugging_bgp, + show_debugging_bgp_cmd, + "show debugging [bgp]", + SHOW_STR + DEBUG_STR + BGP_STR) +{ + vty_out(vty, "BGP debugging status:\n"); + + if (BGP_DEBUG(as4, AS4)) + vty_out(vty, " BGP as4 debugging is on\n"); + + if (BGP_DEBUG(as4, AS4_SEGMENT)) + vty_out(vty, " BGP as4 aspath segment debugging is on\n"); + + if (BGP_DEBUG(bestpath, BESTPATH)) + bgp_debug_list_print(vty, " BGP bestpath debugging is on", + bgp_debug_bestpath_prefixes); + + if (BGP_DEBUG(keepalive, KEEPALIVE)) + bgp_debug_list_print(vty, " BGP keepalives debugging is on", + bgp_debug_keepalive_peers); + + if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) + bgp_debug_list_print(vty, + " BGP neighbor-events debugging is on", + bgp_debug_neighbor_events_peers); + + if (BGP_DEBUG(nht, NHT)) + vty_out(vty, " BGP next-hop tracking debugging is on\n"); + + if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) + vty_out(vty, " BGP update-groups debugging is on\n"); + + if (BGP_DEBUG(update, UPDATE_PREFIX)) + bgp_debug_list_print(vty, " BGP updates debugging is on", + bgp_debug_update_prefixes); + + if (BGP_DEBUG(update, UPDATE_IN)) + bgp_debug_list_print(vty, + " BGP updates debugging is on (inbound)", + bgp_debug_update_in_peers); + + if (BGP_DEBUG(update, UPDATE_OUT)) + bgp_debug_list_print(vty, + " BGP updates debugging is on (outbound)", + bgp_debug_update_out_peers); + + if (BGP_DEBUG(zebra, ZEBRA)) + bgp_debug_list_print(vty, " BGP zebra debugging is on", + bgp_debug_zebra_prefixes); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + vty_out(vty, " BGP graceful-restart debugging is on\n"); + + if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) + vty_out(vty, " BGP allow martian next hop debugging is on\n"); + + if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) + vty_out(vty, + " BGP route leak from vrf to vpn debugging is on\n"); + if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) + vty_out(vty, + " BGP route leak to vrf from vpn debugging is on\n"); + if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) + vty_out(vty, " BGP vpn route-map event debugging is on\n"); + if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) + vty_out(vty, " BGP vpn label event debugging is on\n"); + if (BGP_DEBUG(flowspec, FLOWSPEC)) + vty_out(vty, " BGP flowspec debugging is on\n"); + if (BGP_DEBUG(labelpool, LABELPOOL)) + vty_out(vty, " BGP labelpool debugging is on\n"); + + if (BGP_DEBUG(pbr, PBR)) + vty_out(vty, " BGP policy based routing debugging is on\n"); + if (BGP_DEBUG(pbr, PBR_ERROR)) + vty_out(vty, " BGP policy based routing error debugging is on\n"); + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + vty_out(vty, " BGP EVPN-MH ES debugging is on\n"); + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + vty_out(vty, " BGP EVPN-MH route debugging is on\n"); + + if (BGP_DEBUG(bfd, BFD_LIB)) + vty_out(vty, " BGP BFD library debugging is on\n"); + + if (BGP_DEBUG(cond_adv, COND_ADV)) + vty_out(vty, + " BGP conditional advertisement debugging is on\n"); + + cmd_show_lib_debugs(vty); + + return CMD_SUCCESS; +} + +static int bgp_config_write_debug(struct vty *vty) +{ + int write = 0; + + if (CONF_BGP_DEBUG(as4, AS4)) { + vty_out(vty, "debug bgp as4\n"); + write++; + } + + if (CONF_BGP_DEBUG(as4, AS4_SEGMENT)) { + vty_out(vty, "debug bgp as4 segment\n"); + write++; + } + + if (CONF_BGP_DEBUG(bestpath, BESTPATH)) { + write += bgp_debug_list_conf_print(vty, "debug bgp bestpath", + bgp_debug_bestpath_prefixes); + } + + if (CONF_BGP_DEBUG(keepalive, KEEPALIVE)) { + write += bgp_debug_list_conf_print(vty, "debug bgp keepalives", + bgp_debug_keepalive_peers); + } + + if (CONF_BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) { + write += bgp_debug_list_conf_print( + vty, "debug bgp neighbor-events", + bgp_debug_neighbor_events_peers); + } + + if (CONF_BGP_DEBUG(nht, NHT)) { + vty_out(vty, "debug bgp nht\n"); + write++; + } + + if (CONF_BGP_DEBUG(update_groups, UPDATE_GROUPS)) { + vty_out(vty, "debug bgp update-groups\n"); + write++; + } + + if (CONF_BGP_DEBUG(update, UPDATE_PREFIX)) { + write += bgp_debug_list_conf_print(vty, + "debug bgp updates prefix", + bgp_debug_update_prefixes); + } + + if (CONF_BGP_DEBUG(update, UPDATE_IN)) { + write += bgp_debug_list_conf_print(vty, "debug bgp updates in", + bgp_debug_update_in_peers); + } + + if (CONF_BGP_DEBUG(update, UPDATE_OUT)) { + write += bgp_debug_list_conf_print(vty, "debug bgp updates out", + bgp_debug_update_out_peers); + } + + if (CONF_BGP_DEBUG(zebra, ZEBRA)) { + if (!bgp_debug_zebra_prefixes + || list_isempty(bgp_debug_zebra_prefixes)) { + vty_out(vty, "debug bgp zebra\n"); + write++; + } else { + write += bgp_debug_list_conf_print( + vty, "debug bgp zebra prefix", + bgp_debug_zebra_prefixes); + } + } + + if (CONF_BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { + vty_out(vty, "debug bgp allow-martians\n"); + write++; + } + + if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) { + vty_out(vty, "debug bgp vpn leak-from-vrf\n"); + write++; + } + if (CONF_BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) { + vty_out(vty, "debug bgp vpn leak-to-vrf\n"); + write++; + } + if (CONF_BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) { + vty_out(vty, "debug bgp vpn rmap-event\n"); + write++; + } + if (CONF_BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { + vty_out(vty, "debug bgp vpn label\n"); + write++; + } + if (CONF_BGP_DEBUG(flowspec, FLOWSPEC)) { + vty_out(vty, "debug bgp flowspec\n"); + write++; + } + if (CONF_BGP_DEBUG(labelpool, LABELPOOL)) { + vty_out(vty, "debug bgp labelpool\n"); + write++; + } + + if (CONF_BGP_DEBUG(pbr, PBR)) { + vty_out(vty, "debug bgp pbr\n"); + write++; + } + if (CONF_BGP_DEBUG(pbr, PBR_ERROR)) { + vty_out(vty, "debug bgp pbr error\n"); + write++; + } + + if (CONF_BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { + vty_out(vty, "debug bgp graceful-restart\n"); + write++; + } + + if (CONF_BGP_DEBUG(evpn_mh, EVPN_MH_ES)) { + vty_out(vty, "debug bgp evpn mh es\n"); + write++; + } + if (CONF_BGP_DEBUG(evpn_mh, EVPN_MH_RT)) { + vty_out(vty, "debug bgp evpn mh route\n"); + write++; + } + + if (CONF_BGP_DEBUG(bfd, BFD_LIB)) { + vty_out(vty, "debug bgp bfd\n"); + write++; + } + + if (CONF_BGP_DEBUG(cond_adv, COND_ADV)) { + vty_out(vty, "debug bgp conditional-advertisement\n"); + write++; + } + + return write; +} + +static int bgp_config_write_debug(struct vty *vty); +static struct cmd_node debug_node = { + .name = "debug", + .node = DEBUG_NODE, + .prompt = "", + .config_write = bgp_config_write_debug, +}; + +void bgp_debug_init(void) +{ + install_node(&debug_node); + + install_element(ENABLE_NODE, &show_debugging_bgp_cmd); + + install_element(ENABLE_NODE, &debug_bgp_as4_cmd); + install_element(CONFIG_NODE, &debug_bgp_as4_cmd); + install_element(ENABLE_NODE, &debug_bgp_as4_segment_cmd); + install_element(CONFIG_NODE, &debug_bgp_as4_segment_cmd); + + install_element(ENABLE_NODE, &debug_bgp_neighbor_events_cmd); + install_element(CONFIG_NODE, &debug_bgp_neighbor_events_cmd); + install_element(ENABLE_NODE, &debug_bgp_nht_cmd); + install_element(CONFIG_NODE, &debug_bgp_nht_cmd); + install_element(ENABLE_NODE, &debug_bgp_keepalive_cmd); + install_element(CONFIG_NODE, &debug_bgp_keepalive_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_cmd); + install_element(ENABLE_NODE, &debug_bgp_zebra_cmd); + install_element(CONFIG_NODE, &debug_bgp_zebra_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_groups_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_groups_cmd); + install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd); + install_element(CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd); + + install_element(ENABLE_NODE, &debug_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &debug_bgp_graceful_restart_cmd); + + /* debug bgp updates (in|out) */ + install_element(ENABLE_NODE, &debug_bgp_update_direct_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_direct_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_direct_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_direct_cmd); + + /* debug bgp updates (in|out) A.B.C.D */ + install_element(ENABLE_NODE, &debug_bgp_update_direct_peer_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_direct_peer_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_direct_peer_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_direct_peer_cmd); + + /* debug bgp updates prefix A.B.C.D/M */ + install_element(ENABLE_NODE, &debug_bgp_update_prefix_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_prefix_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); + + /* debug bgp zebra prefix A.B.C.D/M */ + install_element(ENABLE_NODE, &debug_bgp_zebra_prefix_cmd); + install_element(CONFIG_NODE, &debug_bgp_zebra_prefix_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_zebra_prefix_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_zebra_prefix_cmd); + + install_element(ENABLE_NODE, &no_debug_bgp_as4_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_as4_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_as4_segment_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_as4_segment_cmd); + + /* debug bgp neighbor-events A.B.C.D */ + install_element(ENABLE_NODE, &debug_bgp_neighbor_events_peer_cmd); + install_element(CONFIG_NODE, &debug_bgp_neighbor_events_peer_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_neighbor_events_peer_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_neighbor_events_peer_cmd); + + /* debug bgp keepalive A.B.C.D */ + install_element(ENABLE_NODE, &debug_bgp_keepalive_peer_cmd); + install_element(CONFIG_NODE, &debug_bgp_keepalive_peer_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_keepalive_peer_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_keepalive_peer_cmd); + + install_element(ENABLE_NODE, &no_debug_bgp_neighbor_events_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_neighbor_events_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_nht_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_nht_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_keepalive_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_keepalive_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_zebra_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_zebra_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_groups_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_groups_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_bestpath_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_bestpath_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd); + + install_element(ENABLE_NODE, &no_debug_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_graceful_restart_cmd); + + install_element(ENABLE_NODE, &debug_bgp_vpn_cmd); + install_element(CONFIG_NODE, &debug_bgp_vpn_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_vpn_cmd); + + install_element(ENABLE_NODE, &debug_bgp_labelpool_cmd); + install_element(CONFIG_NODE, &debug_bgp_labelpool_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_labelpool_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_labelpool_cmd); + + /* debug bgp pbr */ + install_element(ENABLE_NODE, &debug_bgp_pbr_cmd); + install_element(CONFIG_NODE, &debug_bgp_pbr_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_pbr_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_pbr_cmd); + + install_element(ENABLE_NODE, &debug_bgp_evpn_mh_cmd); + install_element(CONFIG_NODE, &debug_bgp_evpn_mh_cmd); + + /* debug bgp bfd */ + install_element(ENABLE_NODE, &debug_bgp_bfd_cmd); + install_element(CONFIG_NODE, &debug_bgp_bfd_cmd); + + /* debug bgp conditional advertisement */ + install_element(ENABLE_NODE, &debug_bgp_cond_adv_cmd); + install_element(CONFIG_NODE, &debug_bgp_cond_adv_cmd); +} + +/* Return true if this prefix is on the per_prefix_list of prefixes to debug + * for BGP_DEBUG_TYPE + */ +static int bgp_debug_per_prefix(const struct prefix *p, + unsigned long term_bgp_debug_type, + unsigned int BGP_DEBUG_TYPE, + struct list *per_prefix_list) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + if (term_bgp_debug_type & BGP_DEBUG_TYPE) { + /* We are debugging all prefixes so return true */ + if (!per_prefix_list || list_isempty(per_prefix_list)) + return 1; + + else { + if (!p) + return 0; + + for (ALL_LIST_ELEMENTS(per_prefix_list, node, nnode, + filter)) + if (filter->p->prefixlen == p->prefixlen + && prefix_match(filter->p, p)) + return 1; + + return 0; + } + } + + return 0; +} + +/* Return true if this peer is on the per_peer_list of peers to debug + * for BGP_DEBUG_TYPE + */ +static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, + unsigned int BGP_DEBUG_TYPE, + struct list *per_peer_list) +{ + struct bgp_debug_filter *filter; + struct listnode *node, *nnode; + + if (term_bgp_debug_type & BGP_DEBUG_TYPE) { + /* We are debugging all peers so return true */ + if (!per_peer_list || list_isempty(per_peer_list)) + return true; + + else { + if (!host) + return false; + + for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, + filter)) + if (strcmp(filter->host, host) == 0) + return true; + + return false; + } + } + + return false; +} + +bool bgp_debug_neighbor_events(const struct peer *peer) +{ + char *host = NULL; + + if (peer) + host = peer->host; + + return bgp_debug_per_peer(host, term_bgp_debug_neighbor_events, + BGP_DEBUG_NEIGHBOR_EVENTS, + bgp_debug_neighbor_events_peers); +} + +bool bgp_debug_keepalive(const struct peer *peer) +{ + char *host = NULL; + + if (peer) + host = peer->host; + + return bgp_debug_per_peer(host, term_bgp_debug_keepalive, + BGP_DEBUG_KEEPALIVE, + bgp_debug_keepalive_peers); +} + +bool bgp_debug_update(const struct peer *peer, const struct prefix *p, + struct update_group *updgrp, unsigned int inbound) +{ + char *host = NULL; + + if (peer) + host = peer->host; + + if (inbound) { + if (bgp_debug_per_peer(host, term_bgp_debug_update, + BGP_DEBUG_UPDATE_IN, + bgp_debug_update_in_peers)) + return true; + } + + /* outbound */ + else { + if (bgp_debug_per_peer(host, term_bgp_debug_update, + BGP_DEBUG_UPDATE_OUT, + bgp_debug_update_out_peers)) + return true; + + /* Check if update debugging implicitly enabled for the group. + */ + if (updgrp && UPDGRP_DBG_ON(updgrp)) + return true; + } + + + if (BGP_DEBUG(update, UPDATE_PREFIX)) { + if (bgp_debug_per_prefix(p, term_bgp_debug_update, + BGP_DEBUG_UPDATE_PREFIX, + bgp_debug_update_prefixes)) + return true; + } + + return false; +} + +bool bgp_debug_bestpath(struct bgp_dest *dest) +{ + if (BGP_DEBUG(bestpath, BESTPATH)) { + if (bgp_debug_per_prefix( + bgp_dest_get_prefix(dest), term_bgp_debug_bestpath, + BGP_DEBUG_BESTPATH, bgp_debug_bestpath_prefixes)) + return true; + } + + return false; +} + +bool bgp_debug_zebra(const struct prefix *p) +{ + if (BGP_DEBUG(zebra, ZEBRA)) { + if (bgp_debug_per_prefix(p, term_bgp_debug_zebra, + BGP_DEBUG_ZEBRA, + bgp_debug_zebra_prefixes)) + return true; + } + + return false; +} + +const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, + const struct prefix_rd *prd, + union prefixconstptr pu, + mpls_label_t *label, uint32_t num_labels, + int addpath_valid, uint32_t addpath_id, + struct bgp_route_evpn *overlay_index, + char *str, int size) +{ + char tag_buf[30]; + char overlay_index_buf[INET6_ADDRSTRLEN + 14]; + const struct prefix_evpn *evp; + int len = 0; + + /* ' with addpath ID ' 17 + * max strlen of uint32 + 10 + * +/- (just in case) + 1 + * null terminator + 1 + * ============================ 29 */ + char pathid_buf[30]; + + if (size < BGP_PRD_PATH_STRLEN) + return NULL; + + /* Note: Path-id is created by default, but only included in update + * sometimes. */ + pathid_buf[0] = '\0'; + if (addpath_valid) + snprintf(pathid_buf, sizeof(pathid_buf), " with addpath ID %u", + addpath_id); + + overlay_index_buf[0] = '\0'; + if (overlay_index && overlay_index->type == OVERLAY_INDEX_GATEWAY_IP) { + char obuf[INET6_ADDRSTRLEN]; + + obuf[0] = '\0'; + evp = pu.evp; + if (is_evpn_prefix_ipaddr_v4(evp)) + inet_ntop(AF_INET, &overlay_index->gw_ip, obuf, + sizeof(obuf)); + else if (is_evpn_prefix_ipaddr_v6(evp)) + inet_ntop(AF_INET6, &overlay_index->gw_ip, obuf, + sizeof(obuf)); + + snprintf(overlay_index_buf, sizeof(overlay_index_buf), + " gateway IP %s", obuf); + } + + tag_buf[0] = '\0'; + if (bgp_labeled_safi(safi) && num_labels) { + + if (safi == SAFI_EVPN) { + char tag_buf2[20]; + + bgp_evpn_label2str(label, num_labels, tag_buf2, 20); + snprintf(tag_buf, sizeof(tag_buf), " label %s", + tag_buf2); + } else { + uint32_t label_value; + + label_value = decode_label(label); + snprintf(tag_buf, sizeof(tag_buf), " label %u", + label_value); + } + } + + if (prd) { + len += snprintfrr(str + len, size - len, "RD "); + len += snprintfrr(str + len, size - len, + BGP_RD_AS_FORMAT(bgp_get_asnotation(NULL)), + prd); + snprintfrr(str + len, size - len, " %pFX%s%s%s %s %s", pu.p, + overlay_index_buf, tag_buf, pathid_buf, afi2str(afi), + safi2str(safi)); + } else if (safi == SAFI_FLOWSPEC) { + char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX]; + const struct prefix_fs *fs = pu.fs; + + bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr, + fs->prefix.prefixlen, + return_string, + NLRI_STRING_FORMAT_DEBUG, NULL, + family2afi(fs->prefix.family)); + snprintf(str, size, "FS %s Match{%s}", afi2str(afi), + return_string); + } else + snprintfrr(str, size, "%pFX%s%s %s %s", pu.p, tag_buf, + pathid_buf, afi2str(afi), safi2str(safi)); + + return str; +} |