mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 08:33:44 +00:00 
			
		
		
		
	 04dfcb14ff
			
		
	
	
		04dfcb14ff
		
	
	
	
	
		
			
			More details: https://www.rfc-editor.org/rfc/rfc8810.html Not sure if we want to maintain the old code more. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
		
			
				
	
	
		
			21879 lines
		
	
	
		
			637 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			21879 lines
		
	
	
		
			637 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /* BGP VTY interface.
 | |
|  * Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
 | |
|  */
 | |
| 
 | |
| #include <zebra.h>
 | |
| 
 | |
| #include "command.h"
 | |
| #include "lib/json.h"
 | |
| #include "lib/sockopt.h"
 | |
| #include "lib_errors.h"
 | |
| #include "lib/zclient.h"
 | |
| #include "lib/printfrr.h"
 | |
| #include "prefix.h"
 | |
| #include "plist.h"
 | |
| #include "buffer.h"
 | |
| #include "linklist.h"
 | |
| #include "stream.h"
 | |
| #include "frrevent.h"
 | |
| #include "log.h"
 | |
| #include "memory.h"
 | |
| #include "lib_vty.h"
 | |
| #include "hash.h"
 | |
| #include "queue.h"
 | |
| #include "filter.h"
 | |
| #include "frrstr.h"
 | |
| #include "asn.h"
 | |
| 
 | |
| #include "bgpd/bgpd.h"
 | |
| #include "bgpd/bgp_attr_evpn.h"
 | |
| #include "bgpd/bgp_advertise.h"
 | |
| #include "bgpd/bgp_attr.h"
 | |
| #include "bgpd/bgp_aspath.h"
 | |
| #include "bgpd/bgp_community.h"
 | |
| #include "bgpd/bgp_community_alias.h"
 | |
| #include "bgpd/bgp_ecommunity.h"
 | |
| #include "bgpd/bgp_lcommunity.h"
 | |
| #include "bgpd/bgp_damp.h"
 | |
| #include "bgpd/bgp_debug.h"
 | |
| #include "bgpd/bgp_errors.h"
 | |
| #include "bgpd/bgp_fsm.h"
 | |
| #include "bgpd/bgp_nht.h"
 | |
| #include "bgpd/bgp_nexthop.h"
 | |
| #include "bgpd/bgp_network.h"
 | |
| #include "bgpd/bgp_open.h"
 | |
| #include "bgpd/bgp_regex.h"
 | |
| #include "bgpd/bgp_route.h"
 | |
| #include "bgpd/bgp_mplsvpn.h"
 | |
| #include "bgpd/bgp_zebra.h"
 | |
| #include "bgpd/bgp_table.h"
 | |
| #include "bgpd/bgp_vty.h"
 | |
| #include "bgpd/bgp_mpath.h"
 | |
| #include "bgpd/bgp_packet.h"
 | |
| #include "bgpd/bgp_updgrp.h"
 | |
| #include "bgpd/bgp_bfd.h"
 | |
| #include "bgpd/bgp_io.h"
 | |
| #include "bgpd/bgp_evpn.h"
 | |
| #include "bgpd/bgp_evpn_vty.h"
 | |
| #include "bgpd/bgp_evpn_mh.h"
 | |
| #include "bgpd/bgp_addpath.h"
 | |
| #include "bgpd/bgp_mac.h"
 | |
| #include "bgpd/bgp_flowspec.h"
 | |
| #include "bgpd/bgp_conditional_adv.h"
 | |
| #ifdef ENABLE_BGP_VNC
 | |
| #include "bgpd/rfapi/bgp_rfapi_cfg.h"
 | |
| #endif
 | |
| 
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
 | |
| 	{
 | |
| 		.val_bool = false,
 | |
| 			.match_profile = "traditional",
 | |
| 			.match_version = "< 7.4",
 | |
| 	},
 | |
| 	{ .val_bool = true },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME,
 | |
| 	{ .val_bool = true, .match_profile = "datacenter", },
 | |
| 	{ .val_bool = false },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_SHOW_NEXTHOP_HOSTNAME,
 | |
| 	{ .val_bool = true, .match_profile = "datacenter", },
 | |
| 	{ .val_bool = false },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES,
 | |
| 	{ .val_bool = true, .match_profile = "datacenter", },
 | |
| 	{ .val_bool = false },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED,
 | |
| 	{ .val_bool = true, .match_profile = "datacenter", },
 | |
| 	{ .val_bool = false },
 | |
| );
 | |
| FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
 | |
| 	{ .val_ulong = 10, .match_profile = "datacenter", },
 | |
| 	{ .val_ulong = 120 },
 | |
| );
 | |
| FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME,
 | |
| 	{ .val_ulong = 9, .match_profile = "datacenter", },
 | |
| 	{ .val_ulong = 180 },
 | |
| );
 | |
| FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE,
 | |
| 	{ .val_ulong = 3, .match_profile = "datacenter", },
 | |
| 	{ .val_ulong = 60 },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY,
 | |
| 	{ .val_bool = false, .match_profile = "datacenter", },
 | |
| 	{ .val_bool = false, .match_version = "< 7.4", },
 | |
| 	{ .val_bool = true },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
 | |
| 	{ .val_bool = false, .match_version = "< 7.6", },
 | |
| 	{ .val_bool = true },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_GRACEFUL_NOTIFICATION,
 | |
| 	{ .val_bool = false, .match_version = "< 8.3", },
 | |
| 	{ .val_bool = true },
 | |
| );
 | |
| FRR_CFG_DEFAULT_BOOL(BGP_HARD_ADMIN_RESET,
 | |
| 	{ .val_bool = false, .match_version = "< 8.3", },
 | |
| 	{ .val_bool = true },
 | |
| );
 | |
| 
 | |
| DEFINE_HOOK(bgp_inst_config_write,
 | |
| 		(struct bgp *bgp, struct vty *vty),
 | |
| 		(bgp, vty));
 | |
| DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
 | |
| DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
 | |
| 
 | |
| static struct peer_group *listen_range_exists(struct bgp *bgp,
 | |
| 					      struct prefix *range, int exact);
 | |
| 
 | |
| /* Show BGP peer's information. */
 | |
| enum show_type {
 | |
| 	show_all,
 | |
| 	show_peer,
 | |
| 	show_ipv4_all,
 | |
| 	show_ipv6_all,
 | |
| 	show_ipv4_peer,
 | |
| 	show_ipv6_peer
 | |
| };
 | |
| 
 | |
| static struct peer_group *listen_range_exists(struct bgp *bgp,
 | |
| 					      struct prefix *range, int exact);
 | |
| 
 | |
| static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
 | |
| 						      struct bgp *bgp);
 | |
| 
 | |
| static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
 | |
| 						      enum show_type type,
 | |
| 						      const char *ip_str,
 | |
| 						      afi_t afi, bool use_json);
 | |
| 
 | |
| static enum node_type bgp_node_type(afi_t afi, safi_t safi)
 | |
| {
 | |
| 	switch (afi) {
 | |
| 	case AFI_IP:
 | |
| 		switch (safi) {
 | |
| 		case SAFI_UNICAST:
 | |
| 			return BGP_IPV4_NODE;
 | |
| 		case SAFI_MULTICAST:
 | |
| 			return BGP_IPV4M_NODE;
 | |
| 		case SAFI_LABELED_UNICAST:
 | |
| 			return BGP_IPV4L_NODE;
 | |
| 		case SAFI_MPLS_VPN:
 | |
| 			return BGP_VPNV4_NODE;
 | |
| 		case SAFI_FLOWSPEC:
 | |
| 			return BGP_FLOWSPECV4_NODE;
 | |
| 		case SAFI_UNSPEC:
 | |
| 		case SAFI_ENCAP:
 | |
| 		case SAFI_EVPN:
 | |
| 		case SAFI_MAX:
 | |
| 			/* not expected */
 | |
| 			return BGP_IPV4_NODE;
 | |
| 		}
 | |
| 		break;
 | |
| 	case AFI_IP6:
 | |
| 		switch (safi) {
 | |
| 		case SAFI_UNICAST:
 | |
| 			return BGP_IPV6_NODE;
 | |
| 		case SAFI_MULTICAST:
 | |
| 			return BGP_IPV6M_NODE;
 | |
| 		case SAFI_LABELED_UNICAST:
 | |
| 			return BGP_IPV6L_NODE;
 | |
| 		case SAFI_MPLS_VPN:
 | |
| 			return BGP_VPNV6_NODE;
 | |
| 		case SAFI_FLOWSPEC:
 | |
| 			return BGP_FLOWSPECV6_NODE;
 | |
| 		case SAFI_UNSPEC:
 | |
| 		case SAFI_ENCAP:
 | |
| 		case SAFI_EVPN:
 | |
| 		case SAFI_MAX:
 | |
| 			/* not expected and the return value seems wrong */
 | |
| 			return BGP_IPV4_NODE;
 | |
| 		}
 | |
| 		break;
 | |
| 	case AFI_L2VPN:
 | |
| 		return BGP_EVPN_NODE;
 | |
| 	case AFI_UNSPEC:
 | |
| 	case AFI_MAX:
 | |
| 		// We should never be here but to clarify the switch statement..
 | |
| 		return BGP_IPV4_NODE;
 | |
| 	}
 | |
| 
 | |
| 	// Impossible to happen
 | |
| 	return BGP_IPV4_NODE;
 | |
| }
 | |
| 
 | |
| static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
 | |
| {
 | |
| 	if (afi == AFI_IP) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			return "IPv4 Unicast";
 | |
| 		if (safi == SAFI_MULTICAST)
 | |
| 			return "IPv4 Multicast";
 | |
| 		if (safi == SAFI_LABELED_UNICAST)
 | |
| 			return "IPv4 Labeled Unicast";
 | |
| 		if (safi == SAFI_MPLS_VPN)
 | |
| 			return "IPv4 VPN";
 | |
| 		if (safi == SAFI_ENCAP)
 | |
| 			return "IPv4 Encap";
 | |
| 		if (safi == SAFI_FLOWSPEC)
 | |
| 			return "IPv4 Flowspec";
 | |
| 	} else if (afi == AFI_IP6) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			return "IPv6 Unicast";
 | |
| 		if (safi == SAFI_MULTICAST)
 | |
| 			return "IPv6 Multicast";
 | |
| 		if (safi == SAFI_LABELED_UNICAST)
 | |
| 			return "IPv6 Labeled Unicast";
 | |
| 		if (safi == SAFI_MPLS_VPN)
 | |
| 			return "IPv6 VPN";
 | |
| 		if (safi == SAFI_ENCAP)
 | |
| 			return "IPv6 Encap";
 | |
| 		if (safi == SAFI_FLOWSPEC)
 | |
| 			return "IPv6 Flowspec";
 | |
| 	} else if (afi == AFI_L2VPN) {
 | |
| 		if (safi == SAFI_EVPN)
 | |
| 			return "L2VPN EVPN";
 | |
| 	}
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Please note that we have intentionally camelCased
 | |
|  * the return strings here.  So if you want
 | |
|  * to use this function, please ensure you
 | |
|  * are doing this within json output
 | |
|  */
 | |
| static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
 | |
| {
 | |
| 	if (afi == AFI_IP) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			return "ipv4Unicast";
 | |
| 		if (safi == SAFI_MULTICAST)
 | |
| 			return "ipv4Multicast";
 | |
| 		if (safi == SAFI_LABELED_UNICAST)
 | |
| 			return "ipv4LabeledUnicast";
 | |
| 		if (safi == SAFI_MPLS_VPN)
 | |
| 			return "ipv4Vpn";
 | |
| 		if (safi == SAFI_ENCAP)
 | |
| 			return "ipv4Encap";
 | |
| 		if (safi == SAFI_FLOWSPEC)
 | |
| 			return "ipv4Flowspec";
 | |
| 	} else if (afi == AFI_IP6) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			return "ipv6Unicast";
 | |
| 		if (safi == SAFI_MULTICAST)
 | |
| 			return "ipv6Multicast";
 | |
| 		if (safi == SAFI_LABELED_UNICAST)
 | |
| 			return "ipv6LabeledUnicast";
 | |
| 		if (safi == SAFI_MPLS_VPN)
 | |
| 			return "ipv6Vpn";
 | |
| 		if (safi == SAFI_ENCAP)
 | |
| 			return "ipv6Encap";
 | |
| 		if (safi == SAFI_FLOWSPEC)
 | |
| 			return "ipv6Flowspec";
 | |
| 	} else if (afi == AFI_L2VPN) {
 | |
| 		if (safi == SAFI_EVPN)
 | |
| 			return "l2VpnEvpn";
 | |
| 	}
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| 
 | |
| /* unset srv6 locator */
 | |
| static int bgp_srv6_locator_unset(struct bgp *bgp)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct srv6_locator_chunk *chunk;
 | |
| 	struct bgp_srv6_function *func;
 | |
| 	struct bgp *bgp_vrf;
 | |
| 
 | |
| 	/* release chunk notification via ZAPI */
 | |
| 	ret = bgp_zebra_srv6_manager_release_locator_chunk(
 | |
| 			bgp->srv6_locator_name);
 | |
| 	if (ret < 0)
 | |
| 		return -1;
 | |
| 
 | |
| 	/* refresh chunks */
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk)) {
 | |
| 		listnode_delete(bgp->srv6_locator_chunks, chunk);
 | |
| 		srv6_locator_chunk_free(&chunk);
 | |
| 	}
 | |
| 
 | |
| 	/* refresh functions */
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) {
 | |
| 		listnode_delete(bgp->srv6_functions, func);
 | |
| 		XFREE(MTYPE_BGP_SRV6_FUNCTION, func);
 | |
| 	}
 | |
| 
 | |
| 	/* refresh tovpn_sid */
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
 | |
| 		if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
 | |
| 			continue;
 | |
| 
 | |
| 		/* refresh vpnv4 tovpn_sid */
 | |
| 		XFREE(MTYPE_BGP_SRV6_SID,
 | |
| 		      bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
 | |
| 
 | |
| 		/* refresh vpnv6 tovpn_sid */
 | |
| 		XFREE(MTYPE_BGP_SRV6_SID,
 | |
| 		      bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
 | |
| 
 | |
| 		/* refresh per-vrf tovpn_sid */
 | |
| 		XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
 | |
| 	}
 | |
| 
 | |
| 	/* update vpn bgp processes */
 | |
| 	vpn_leak_postchange_all();
 | |
| 
 | |
| 	/* refresh tovpn_sid_locator */
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
 | |
| 		if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
 | |
| 			continue;
 | |
| 
 | |
| 		/* refresh vpnv4 tovpn_sid_locator */
 | |
| 		srv6_locator_chunk_free(
 | |
| 			&bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
 | |
| 
 | |
| 		/* refresh vpnv6 tovpn_sid_locator */
 | |
| 		srv6_locator_chunk_free(
 | |
| 			&bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
 | |
| 
 | |
| 		/* refresh per-vrf tovpn_sid_locator */
 | |
| 		srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
 | |
| 	}
 | |
| 
 | |
| 	/* clear locator name */
 | |
| 	memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* Utility function to get address family from current node.  */
 | |
| afi_t bgp_node_afi(struct vty *vty)
 | |
| {
 | |
| 	afi_t afi;
 | |
| 	switch (vty->node) {
 | |
| 	case BGP_IPV6_NODE:
 | |
| 	case BGP_IPV6M_NODE:
 | |
| 	case BGP_IPV6L_NODE:
 | |
| 	case BGP_VPNV6_NODE:
 | |
| 	case BGP_FLOWSPECV6_NODE:
 | |
| 		afi = AFI_IP6;
 | |
| 		break;
 | |
| 	case BGP_EVPN_NODE:
 | |
| 		afi = AFI_L2VPN;
 | |
| 		break;
 | |
| 	default:
 | |
| 		afi = AFI_IP;
 | |
| 		break;
 | |
| 	}
 | |
| 	return afi;
 | |
| }
 | |
| 
 | |
| /* Utility function to get subsequent address family from current
 | |
|    node.  */
 | |
| safi_t bgp_node_safi(struct vty *vty)
 | |
| {
 | |
| 	safi_t safi;
 | |
| 	switch (vty->node) {
 | |
| 	case BGP_VPNV4_NODE:
 | |
| 	case BGP_VPNV6_NODE:
 | |
| 		safi = SAFI_MPLS_VPN;
 | |
| 		break;
 | |
| 	case BGP_IPV4M_NODE:
 | |
| 	case BGP_IPV6M_NODE:
 | |
| 		safi = SAFI_MULTICAST;
 | |
| 		break;
 | |
| 	case BGP_EVPN_NODE:
 | |
| 		safi = SAFI_EVPN;
 | |
| 		break;
 | |
| 	case BGP_IPV4L_NODE:
 | |
| 	case BGP_IPV6L_NODE:
 | |
| 		safi = SAFI_LABELED_UNICAST;
 | |
| 		break;
 | |
| 	case BGP_FLOWSPECV4_NODE:
 | |
| 	case BGP_FLOWSPECV6_NODE:
 | |
| 		safi = SAFI_FLOWSPEC;
 | |
| 		break;
 | |
| 	default:
 | |
| 		safi = SAFI_UNICAST;
 | |
| 		break;
 | |
| 	}
 | |
| 	return safi;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Converts an AFI in string form to afi_t
 | |
|  *
 | |
|  * @param afi string, one of
 | |
|  *  - "ipv4"
 | |
|  *  - "ipv6"
 | |
|  *  - "l2vpn"
 | |
|  * @return the corresponding afi_t
 | |
|  */
 | |
| afi_t bgp_vty_afi_from_str(const char *afi_str)
 | |
| {
 | |
| 	afi_t afi = AFI_MAX; /* unknown */
 | |
| 	if (strmatch(afi_str, "ipv4"))
 | |
| 		afi = AFI_IP;
 | |
| 	else if (strmatch(afi_str, "ipv6"))
 | |
| 		afi = AFI_IP6;
 | |
| 	else if (strmatch(afi_str, "l2vpn"))
 | |
| 		afi = AFI_L2VPN;
 | |
| 	return afi;
 | |
| }
 | |
| 
 | |
| int argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index,
 | |
| 			    afi_t *afi)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	if (argv_find(argv, argc, "ipv4", index)) {
 | |
| 		ret = 1;
 | |
| 		if (afi)
 | |
| 			*afi = AFI_IP;
 | |
| 	} else if (argv_find(argv, argc, "ipv6", index)) {
 | |
| 		ret = 1;
 | |
| 		if (afi)
 | |
| 			*afi = AFI_IP6;
 | |
| 	} else if (argv_find(argv, argc, "l2vpn", index)) {
 | |
| 		ret = 1;
 | |
| 		if (afi)
 | |
| 			*afi = AFI_L2VPN;
 | |
| 	}
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /* supports <unicast|multicast|vpn|labeled-unicast> */
 | |
| safi_t bgp_vty_safi_from_str(const char *safi_str)
 | |
| {
 | |
| 	safi_t safi = SAFI_MAX; /* unknown */
 | |
| 	if (strmatch(safi_str, "multicast"))
 | |
| 		safi = SAFI_MULTICAST;
 | |
| 	else if (strmatch(safi_str, "unicast"))
 | |
| 		safi = SAFI_UNICAST;
 | |
| 	else if (strmatch(safi_str, "vpn"))
 | |
| 		safi = SAFI_MPLS_VPN;
 | |
| 	else if (strmatch(safi_str, "evpn"))
 | |
| 		safi = SAFI_EVPN;
 | |
| 	else if (strmatch(safi_str, "labeled-unicast"))
 | |
| 		safi = SAFI_LABELED_UNICAST;
 | |
| 	else if (strmatch(safi_str, "flowspec"))
 | |
| 		safi = SAFI_FLOWSPEC;
 | |
| 	return safi;
 | |
| }
 | |
| 
 | |
| int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index,
 | |
| 			     safi_t *safi)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	if (argv_find(argv, argc, "unicast", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_UNICAST;
 | |
| 	} else if (argv_find(argv, argc, "multicast", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_MULTICAST;
 | |
| 	} else if (argv_find(argv, argc, "labeled-unicast", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_LABELED_UNICAST;
 | |
| 	} else if (argv_find(argv, argc, "vpn", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_MPLS_VPN;
 | |
| 	} else if (argv_find(argv, argc, "evpn", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_EVPN;
 | |
| 	} else if (argv_find(argv, argc, "flowspec", index)) {
 | |
| 		ret = 1;
 | |
| 		if (safi)
 | |
| 			*safi = SAFI_FLOWSPEC;
 | |
| 	}
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Convert an afi_t/safi_t pair to matching BGP_DEFAULT_AF* flag.
 | |
|  *
 | |
|  * afi
 | |
|  *    address-family identifier
 | |
|  *
 | |
|  * safi
 | |
|  *    subsequent address-family identifier
 | |
|  *
 | |
|  * Returns:
 | |
|  *    default_af string corresponding to the supplied afi/safi pair.
 | |
|  *    If afi/safi is invalid or if flag for afi/safi doesn't exist,
 | |
|  *    return -1.
 | |
|  */
 | |
| static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi)
 | |
| {
 | |
| 	switch (afi) {
 | |
| 	case AFI_IP:
 | |
| 		switch (safi) {
 | |
| 		case SAFI_UNICAST:
 | |
| 			return "ipv4-unicast";
 | |
| 		case SAFI_MULTICAST:
 | |
| 			return "ipv4-multicast";
 | |
| 		case SAFI_MPLS_VPN:
 | |
| 			return "ipv4-vpn";
 | |
| 		case SAFI_ENCAP:
 | |
| 			return "ipv4-encap";
 | |
| 		case SAFI_LABELED_UNICAST:
 | |
| 			return "ipv4-labeled-unicast";
 | |
| 		case SAFI_FLOWSPEC:
 | |
| 			return "ipv4-flowspec";
 | |
| 		case SAFI_UNSPEC:
 | |
| 		case SAFI_EVPN:
 | |
| 		case SAFI_MAX:
 | |
| 			return "unknown-afi/safi";
 | |
| 		}
 | |
| 		break;
 | |
| 	case AFI_IP6:
 | |
| 		switch (safi) {
 | |
| 		case SAFI_UNICAST:
 | |
| 			return "ipv6-unicast";
 | |
| 		case SAFI_MULTICAST:
 | |
| 			return "ipv6-multicast";
 | |
| 		case SAFI_MPLS_VPN:
 | |
| 			return "ipv6-vpn";
 | |
| 		case SAFI_ENCAP:
 | |
| 			return "ipv6-encap";
 | |
| 		case SAFI_LABELED_UNICAST:
 | |
| 			return "ipv6-labeled-unicast";
 | |
| 		case SAFI_FLOWSPEC:
 | |
| 			return "ipv6-flowspec";
 | |
| 		case SAFI_UNSPEC:
 | |
| 		case SAFI_EVPN:
 | |
| 		case SAFI_MAX:
 | |
| 			return "unknown-afi/safi";
 | |
| 		}
 | |
| 		break;
 | |
| 	case AFI_L2VPN:
 | |
| 		switch (safi) {
 | |
| 		case SAFI_EVPN:
 | |
| 			return "l2vpn-evpn";
 | |
| 		case SAFI_UNICAST:
 | |
| 		case SAFI_MULTICAST:
 | |
| 		case SAFI_MPLS_VPN:
 | |
| 		case SAFI_ENCAP:
 | |
| 		case SAFI_LABELED_UNICAST:
 | |
| 		case SAFI_FLOWSPEC:
 | |
| 		case SAFI_UNSPEC:
 | |
| 		case SAFI_MAX:
 | |
| 			return "unknown-afi/safi";
 | |
| 		}
 | |
| 		break;
 | |
| 	case AFI_UNSPEC:
 | |
| 	case AFI_MAX:
 | |
| 		return "unknown-afi/safi";
 | |
| 	}
 | |
| 	/* all AFIs are accounted for above, so this shouldn't happen */
 | |
| 
 | |
| 	assert(!"Reached end of function where we did not expect to");
 | |
| }
 | |
| 
 | |
| int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
 | |
| 		enum bgp_instance_type inst_type, const char *as_pretty,
 | |
| 		enum asnotation_mode asnotation)
 | |
| {
 | |
| 	int ret = bgp_get(bgp, as, name, inst_type, as_pretty, asnotation);
 | |
| 
 | |
| 	if (ret == BGP_CREATED) {
 | |
| 		bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
 | |
| 			       DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN);
 | |
| 
 | |
| 		if (DFLT_BGP_IMPORT_CHECK)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_IMPORT_CHECK);
 | |
| 		if (DFLT_BGP_SHOW_HOSTNAME)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_SHOW_HOSTNAME);
 | |
| 		if (DFLT_BGP_SHOW_NEXTHOP_HOSTNAME)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME);
 | |
| 		if (DFLT_BGP_LOG_NEIGHBOR_CHANGES)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
 | |
| 		if (DFLT_BGP_DETERMINISTIC_MED)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_DETERMINISTIC_MED);
 | |
| 		if (DFLT_BGP_EBGP_REQUIRES_POLICY)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
 | |
| 		if (DFLT_BGP_SUPPRESS_DUPLICATES)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
 | |
| 		if (DFLT_BGP_GRACEFUL_NOTIFICATION)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);
 | |
| 		if (DFLT_BGP_HARD_ADMIN_RESET)
 | |
| 			SET_FLAG((*bgp)->flags, BGP_FLAG_HARD_ADMIN_RESET);
 | |
| 
 | |
| 		ret = BGP_SUCCESS;
 | |
| 	}
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * bgp_vty_find_and_parse_afi_safi_bgp
 | |
|  *
 | |
|  * For a given 'show ...' command, correctly parse the afi/safi/bgp out from it
 | |
|  * This function *assumes* that the calling function pre-sets the afi/safi/bgp
 | |
|  * to appropriate values for the calling function.  This is to allow the
 | |
|  * calling function to make decisions appropriate for the show command
 | |
|  * that is being parsed.
 | |
|  *
 | |
|  * The show commands are generally of the form:
 | |
|  * "show [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6>
 | |
|  * [<unicast|multicast|vpn|labeled-unicast>]] ..."
 | |
|  *
 | |
|  * Since we use argv_find if the show command in particular doesn't have:
 | |
|  * [ip]
 | |
|  * [<view|vrf> VIEWVRFNAME]
 | |
|  * [<ipv4|ipv6> [<unicast|multicast|vpn|labeled-unicast>]]
 | |
|  * The command parsing should still be ok.
 | |
|  *
 | |
|  * vty  -> The vty for the command so we can output some useful data in
 | |
|  *         the event of a parse error in the vrf.
 | |
|  * argv -> The command tokens
 | |
|  * argc -> How many command tokens we have
 | |
|  * idx  -> The current place in the command, generally should be 0 for this
 | |
|  * function
 | |
|  * afi  -> The parsed afi if it was included in the show command, returned here
 | |
|  * safi -> The parsed safi if it was included in the show command, returned here
 | |
|  * bgp  -> Pointer to the bgp data structure we need to fill in.
 | |
|  * use_json -> json is configured or not
 | |
|  *
 | |
|  * The function returns the correct location in the parse tree for the
 | |
|  * last token found.
 | |
|  *
 | |
|  * Returns 0 for failure to parse correctly, else the idx position of where
 | |
|  * it found the last token.
 | |
|  */
 | |
| int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
 | |
| 					struct cmd_token **argv, int argc,
 | |
| 					int *idx, afi_t *afi, safi_t *safi,
 | |
| 					struct bgp **bgp, bool use_json)
 | |
| {
 | |
| 	char *vrf_name = NULL;
 | |
| 
 | |
| 	assert(afi);
 | |
| 	assert(safi);
 | |
| 	assert(bgp);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "ip", idx))
 | |
| 		*afi = AFI_IP;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "view", idx))
 | |
| 		vrf_name = argv[*idx + 1]->arg;
 | |
| 	else if (argv_find(argv, argc, "vrf", idx)) {
 | |
| 		vrf_name = argv[*idx + 1]->arg;
 | |
| 		if (strmatch(vrf_name, VRF_DEFAULT_NAME))
 | |
| 			vrf_name = NULL;
 | |
| 	}
 | |
| 	if (vrf_name) {
 | |
| 		if (strmatch(vrf_name, "all"))
 | |
| 			*bgp = NULL;
 | |
| 		else {
 | |
| 			*bgp = bgp_lookup_by_name(vrf_name);
 | |
| 			if (!*bgp) {
 | |
| 				if (use_json) {
 | |
| 					json_object *json = NULL;
 | |
| 					json = json_object_new_object();
 | |
| 					json_object_string_add(
 | |
| 					  json, "warning",
 | |
| 					  "View/Vrf is unknown");
 | |
| 					vty_json(vty, json);
 | |
| 				}
 | |
| 				else
 | |
| 					vty_out(vty, "View/Vrf %s is unknown\n",
 | |
| 						vrf_name);
 | |
| 				*idx = 0;
 | |
| 				return 0;
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		*bgp = bgp_get_default();
 | |
| 		if (!*bgp) {
 | |
| 			if (use_json) {
 | |
| 				json_object *json = NULL;
 | |
| 				json = json_object_new_object();
 | |
| 				json_object_string_add(
 | |
| 					json, "warning",
 | |
| 					"Default BGP instance not found");
 | |
| 				vty_json(vty, json);
 | |
| 			}
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"Default BGP instance not found\n");
 | |
| 			*idx = 0;
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find_and_parse_afi(argv, argc, idx, afi))
 | |
| 		argv_find_and_parse_safi(argv, argc, idx, safi);
 | |
| 
 | |
| 	*idx += 1;
 | |
| 	return *idx;
 | |
| }
 | |
| 
 | |
| static bool peer_address_self_check(struct bgp *bgp, union sockunion *su)
 | |
| {
 | |
| 	struct interface *ifp = NULL;
 | |
| 	struct listnode *node;
 | |
| 	struct bgp_listener *listener;
 | |
| 	union sockunion all_su;
 | |
| 
 | |
| 	if (su->sa.sa_family == AF_INET) {
 | |
| 		(void)str2sockunion("0.0.0.0", &all_su);
 | |
| 		ifp = if_lookup_by_ipv4_exact(&su->sin.sin_addr, bgp->vrf_id);
 | |
| 	} else if (su->sa.sa_family == AF_INET6) {
 | |
| 		(void)str2sockunion("::", &all_su);
 | |
| 		ifp = if_lookup_by_ipv6_exact(&su->sin6.sin6_addr,
 | |
| 					      su->sin6.sin6_scope_id,
 | |
| 					      bgp->vrf_id);
 | |
| 	}
 | |
| 
 | |
| 	if (ifp) {
 | |
| 		for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) {
 | |
| 			if (sockunion_family(su) !=
 | |
| 			    sockunion_family(&listener->su))
 | |
| 				continue;
 | |
| 
 | |
| 			/* If 0.0.0.0/:: is a listener, then treat as self and
 | |
| 			 * reject.
 | |
| 			 */
 | |
| 			if (!sockunion_cmp(&listener->su, su) ||
 | |
| 			    !sockunion_cmp(&listener->su, &all_su))
 | |
| 				return true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| /* Utility function for looking up peer from VTY.  */
 | |
| /* This is used only for configuration, so disallow if attempted on
 | |
|  * a dynamic neighbor.
 | |
|  */
 | |
| static struct peer *peer_lookup_vty(struct vty *vty, const char *ip_str)
 | |
| {
 | |
| 	struct bgp *bgp = VTY_GET_CONTEXT(bgp);
 | |
| 	int ret;
 | |
| 	union sockunion su;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	if (!bgp) {
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	ret = str2sockunion(ip_str, &su);
 | |
| 	if (ret < 0) {
 | |
| 		peer = peer_lookup_by_conf_if(bgp, ip_str);
 | |
| 		if (!peer) {
 | |
| 			if ((peer = peer_lookup_by_hostname(bgp, ip_str))
 | |
| 			    == NULL) {
 | |
| 				vty_out(vty,
 | |
| 					"%% Malformed address or name: %s\n",
 | |
| 					ip_str);
 | |
| 				return NULL;
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		peer = peer_lookup(bgp, &su);
 | |
| 		if (!peer) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Specify remote-as or peer-group commands first\n");
 | |
| 			return NULL;
 | |
| 		}
 | |
| 		if (peer_dynamic_neighbor(peer)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Operation not allowed on a dynamic neighbor\n");
 | |
| 			return NULL;
 | |
| 		}
 | |
| 	}
 | |
| 	return peer;
 | |
| }
 | |
| 
 | |
| /* Utility function for looking up peer or peer group.  */
 | |
| /* This is used only for configuration, so disallow if attempted on
 | |
|  * a dynamic neighbor.
 | |
|  */
 | |
| struct peer *peer_and_group_lookup_vty(struct vty *vty, const char *peer_str)
 | |
| {
 | |
| 	struct bgp *bgp = VTY_GET_CONTEXT(bgp);
 | |
| 	int ret;
 | |
| 	union sockunion su;
 | |
| 	struct peer *peer = NULL;
 | |
| 	struct peer_group *group = NULL;
 | |
| 
 | |
| 	if (!bgp) {
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	ret = str2sockunion(peer_str, &su);
 | |
| 	if (ret == 0) {
 | |
| 		/* IP address, locate peer. */
 | |
| 		peer = peer_lookup(bgp, &su);
 | |
| 	} else {
 | |
| 		/* Not IP, could match either peer configured on interface or a
 | |
| 		 * group. */
 | |
| 		peer = peer_lookup_by_conf_if(bgp, peer_str);
 | |
| 		if (!peer)
 | |
| 			group = peer_group_lookup(bgp, peer_str);
 | |
| 	}
 | |
| 
 | |
| 	if (peer) {
 | |
| 		if (peer_dynamic_neighbor(peer)) {
 | |
| 			zlog_warn(
 | |
| 				"%pBP: Operation not allowed on a dynamic neighbor",
 | |
| 				peer);
 | |
| 			vty_out(vty,
 | |
| 				"%% Operation not allowed on a dynamic neighbor\n");
 | |
| 			return NULL;
 | |
| 		}
 | |
| 
 | |
| 		return peer;
 | |
| 	}
 | |
| 
 | |
| 	if (group)
 | |
| 		return group->conf;
 | |
| 
 | |
| 	zlog_warn("Specify remote-as or peer-group commands first before: %s",
 | |
| 		  vty->buf);
 | |
| 	vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
 | |
| {
 | |
| 	const char *str = NULL;
 | |
| 
 | |
| 	switch (ret) {
 | |
| 	case BGP_SUCCESS:
 | |
| 	case BGP_CREATED:
 | |
| 	case BGP_GR_NO_OPERATION:
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_VALUE:
 | |
| 		str = "Invalid value";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_FLAG:
 | |
| 		str = "Invalid flag";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_SHUTDOWN:
 | |
| 		str = "Peer-group has been shutdown. Activate the peer-group first";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_FLAG_CONFLICT:
 | |
| 		str = "Can't set override-capability and strict-capability-match at the same time";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_NO_REMOTE_AS:
 | |
| 		str = "Specify remote-as or peer-group remote AS first";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_CANT_CHANGE:
 | |
| 		str = "Cannot change the peer-group. Deconfigure first";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_MISMATCH:
 | |
| 		str = "Peer is not a member of this peer-group";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_FILTER_CONFLICT:
 | |
| 		str = "Prefix/distribute list can not co-exist";
 | |
| 		break;
 | |
| 	case BGP_ERR_NOT_INTERNAL_PEER:
 | |
| 		str = "Invalid command. Not an internal neighbor";
 | |
| 		break;
 | |
| 	case BGP_ERR_REMOVE_PRIVATE_AS:
 | |
| 		str = "remove-private-AS cannot be configured for IBGP peers";
 | |
| 		break;
 | |
| 	case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS:
 | |
| 		str = "Cannot have local-as same as BGP AS number";
 | |
| 		break;
 | |
| 	case BGP_ERR_TCPSIG_FAILED:
 | |
| 		str = "Error while applying TCP-Sig to session(s)";
 | |
| 		break;
 | |
| 	case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK:
 | |
| 		str = "ebgp-multihop and ttl-security cannot be configured together";
 | |
| 		break;
 | |
| 	case BGP_ERR_NO_IBGP_WITH_TTLHACK:
 | |
| 		str = "ttl-security only allowed for EBGP peers";
 | |
| 		break;
 | |
| 	case BGP_ERR_AS_OVERRIDE:
 | |
| 		str = "as-override cannot be configured for IBGP peers";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT:
 | |
| 		str = "Invalid limit for number of dynamic neighbors";
 | |
| 		break;
 | |
| 	case BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS:
 | |
| 		str = "Dynamic neighbor listen range already exists";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_FOR_DYNAMIC_PEER:
 | |
| 		str = "Operation not allowed on a dynamic neighbor";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_FOR_DIRECT_PEER:
 | |
| 		str = "Operation not allowed on a directly connected neighbor";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_SAFI_CONFLICT:
 | |
| 		str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
 | |
| 		break;
 | |
| 	case BGP_ERR_GR_INVALID_CMD:
 | |
| 		str = "The Graceful Restart command used is not valid at this moment.";
 | |
| 		break;
 | |
| 	case BGP_ERR_GR_OPERATION_FAILED:
 | |
| 		str = "The Graceful Restart Operation failed due to an err.";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_MEMBER:
 | |
| 		str = "Peer-group member cannot override remote-as of peer-group.";
 | |
| 		break;
 | |
| 	case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
 | |
| 		str = "Peer-group members must be all internal or all external.";
 | |
| 		break;
 | |
| 	case BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND:
 | |
| 		str = "Range specified cannot be deleted because it is not part of current config.";
 | |
| 		break;
 | |
| 	case BGP_ERR_INSTANCE_MISMATCH:
 | |
| 		str = "Instance specified does not match the current instance.";
 | |
| 		break;
 | |
| 	case BGP_ERR_NO_INTERFACE_CONFIG:
 | |
| 		str = "Interface specified is not being used for interface based peer.";
 | |
| 		break;
 | |
| 	case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
 | |
| 		str = "No configuration already specified for soft reconfiguration.";
 | |
| 		break;
 | |
| 	case BGP_ERR_AS_MISMATCH:
 | |
| 		str = "BGP is already running.";
 | |
| 		break;
 | |
| 	case BGP_ERR_AF_UNCONFIGURED:
 | |
| 		str = "AFI/SAFI specified is not currently configured.";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_AS:
 | |
| 		str = "Confederation AS specified is the same AS as our AS.";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_ROLE_NAME:
 | |
| 		str = "Invalid role name";
 | |
| 		break;
 | |
| 	case BGP_ERR_INVALID_INTERNAL_ROLE:
 | |
| 		str = "External roles can be set only on eBGP session";
 | |
| 		break;
 | |
| 	}
 | |
| 	if (str) {
 | |
| 		vty_out(vty, "%% %s\n", str);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* BGP clear sort. */
 | |
| enum clear_sort {
 | |
| 	clear_all,
 | |
| 	clear_peer,
 | |
| 	clear_group,
 | |
| 	clear_external,
 | |
| 	clear_as
 | |
| };
 | |
| 
 | |
| static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi,
 | |
| 				safi_t safi, int error)
 | |
| {
 | |
| 	switch (error) {
 | |
| 	case BGP_ERR_AF_UNCONFIGURED:
 | |
| 		if (vty)
 | |
| 			vty_out(vty,
 | |
| 				"%% BGP: Enable %s address family for the neighbor %s\n",
 | |
| 				get_afi_safi_str(afi, safi, false), peer->host);
 | |
| 		else
 | |
| 			zlog_warn(
 | |
| 				"%% BGP: Enable %s address family for the neighbor %s",
 | |
| 				get_afi_safi_str(afi, safi, false), peer->host);
 | |
| 		break;
 | |
| 	case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
 | |
| 		if (vty)
 | |
| 			vty_out(vty,
 | |
| 				"%% BGP: Inbound soft reconfig for %s not possible as it\n      has neither refresh capability, nor inbound soft reconfig\n",
 | |
| 				peer->host);
 | |
| 		else
 | |
| 			zlog_warn(
 | |
| 				"%% BGP: Inbound soft reconfig for %s not possible as it has neither refresh capability, nor inbound soft reconfig",
 | |
| 				peer->host);
 | |
| 		break;
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
 | |
| 			  struct listnode **nnode, enum bgp_clear_type stype)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	struct peer_af *paf;
 | |
| 
 | |
| 	/* if afi/.safi not specified, spin thru all of them */
 | |
| 	if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
 | |
| 		afi_t tmp_afi;
 | |
| 		safi_t tmp_safi;
 | |
| 		enum bgp_af_index index;
 | |
| 
 | |
| 		for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
 | |
| 			paf = peer->peer_af_array[index];
 | |
| 			if (!paf)
 | |
| 				continue;
 | |
| 
 | |
| 			if (paf && paf->subgroup)
 | |
| 				SET_FLAG(paf->subgroup->sflags,
 | |
| 					 SUBGRP_STATUS_FORCE_UPDATES);
 | |
| 
 | |
| 			tmp_afi = paf->afi;
 | |
| 			tmp_safi = paf->safi;
 | |
| 			if (!peer->afc[tmp_afi][tmp_safi])
 | |
| 				continue;
 | |
| 
 | |
| 			if (stype == BGP_CLEAR_SOFT_NONE)
 | |
| 				ret = peer_clear(peer, nnode);
 | |
| 			else
 | |
| 				ret = peer_clear_soft(peer, tmp_afi, tmp_safi,
 | |
| 						      stype);
 | |
| 		}
 | |
| 	/* if afi specified and safi not, spin thru safis on this afi */
 | |
| 	} else if (safi == SAFI_UNSPEC) {
 | |
| 		safi_t tmp_safi;
 | |
| 
 | |
| 		for (tmp_safi = SAFI_UNICAST;
 | |
| 		     tmp_safi < SAFI_MAX; tmp_safi++) {
 | |
| 			if (!peer->afc[afi][tmp_safi])
 | |
| 				continue;
 | |
| 
 | |
| 			paf = peer_af_find(peer, afi, tmp_safi);
 | |
| 			if (paf && paf->subgroup)
 | |
| 				SET_FLAG(paf->subgroup->sflags,
 | |
| 					 SUBGRP_STATUS_FORCE_UPDATES);
 | |
| 
 | |
| 			if (stype == BGP_CLEAR_SOFT_NONE)
 | |
| 				ret = peer_clear(peer, nnode);
 | |
| 			else
 | |
| 				ret = peer_clear_soft(peer, afi,
 | |
| 						      tmp_safi, stype);
 | |
| 		}
 | |
| 	/* both afi/safi specified, let the caller know if not defined */
 | |
| 	} else {
 | |
| 		if (!peer->afc[afi][safi])
 | |
| 			return 1;
 | |
| 
 | |
| 		paf = peer_af_find(peer, afi, safi);
 | |
| 		if (paf && paf->subgroup)
 | |
| 			SET_FLAG(paf->subgroup->sflags,
 | |
| 				 SUBGRP_STATUS_FORCE_UPDATES);
 | |
| 
 | |
| 		if (stype == BGP_CLEAR_SOFT_NONE)
 | |
| 			ret = peer_clear(peer, nnode);
 | |
| 		else
 | |
| 			ret = peer_clear_soft(peer, afi, safi, stype);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /* `clear ip bgp' functions. */
 | |
| static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
 | |
| 		     enum clear_sort sort, enum bgp_clear_type stype,
 | |
| 		     const char *arg)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	bool found = false;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	/* Clear all neighbors. */
 | |
| 	/*
 | |
| 	 * Pass along pointer to next node to peer_clear() when walking all
 | |
| 	 * nodes on the BGP instance as that may get freed if it is a
 | |
| 	 * doppelganger
 | |
| 	 */
 | |
| 	if (sort == clear_all) {
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 
 | |
| 			bgp_peer_gr_flags_update(peer);
 | |
| 
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
 | |
| 				gr_router_detected = true;
 | |
| 
 | |
| 			ret = bgp_peer_clear(peer, afi, safi, &nnode,
 | |
| 							  stype);
 | |
| 
 | |
| 			if (ret < 0)
 | |
| 				bgp_clear_vty_error(vty, peer, afi, safi, ret);
 | |
| 		}
 | |
| 
 | |
| 		if (gr_router_detected
 | |
| 		    && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, false);
 | |
| 		} else if (!gr_router_detected
 | |
| 			   && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, true);
 | |
| 		}
 | |
| 
 | |
| 		/* This is to apply read-only mode on this clear. */
 | |
| 		if (stype == BGP_CLEAR_SOFT_NONE)
 | |
| 			bgp->update_delay_over = 0;
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	/* Clear specified neighbor. */
 | |
| 	if (sort == clear_peer) {
 | |
| 		union sockunion su;
 | |
| 
 | |
| 		/* Make sockunion for lookup. */
 | |
| 		ret = str2sockunion(arg, &su);
 | |
| 		if (ret < 0) {
 | |
| 			peer = peer_lookup_by_conf_if(bgp, arg);
 | |
| 			if (!peer) {
 | |
| 				peer = peer_lookup_by_hostname(bgp, arg);
 | |
| 				if (!peer) {
 | |
| 					vty_out(vty,
 | |
| 						"Malformed address or name: %s\n",
 | |
| 						arg);
 | |
| 					return CMD_WARNING;
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			peer = peer_lookup(bgp, &su);
 | |
| 			if (!peer) {
 | |
| 				vty_out(vty,
 | |
| 					"%% BGP: Unknown neighbor - \"%s\"\n",
 | |
| 					arg);
 | |
| 				return CMD_WARNING;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 		VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 		ret = bgp_peer_clear(peer, afi, safi, NULL, stype);
 | |
| 
 | |
| 		/* if afi/safi not defined for this peer, let caller know */
 | |
| 		if (ret == 1)
 | |
| 			ret = BGP_ERR_AF_UNCONFIGURED;
 | |
| 
 | |
| 		if (ret < 0)
 | |
| 			bgp_clear_vty_error(vty, peer, afi, safi, ret);
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	/* Clear all neighbors belonging to a specific peer-group. */
 | |
| 	if (sort == clear_group) {
 | |
| 		struct peer_group *group;
 | |
| 
 | |
| 		group = peer_group_lookup(bgp, arg);
 | |
| 		if (!group) {
 | |
| 			vty_out(vty, "%% BGP: No such peer-group %s\n", arg);
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 
 | |
| 		for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
 | |
| 			ret = bgp_peer_clear(peer, afi, safi, &nnode, stype);
 | |
| 
 | |
| 			if (ret < 0)
 | |
| 				bgp_clear_vty_error(vty, peer, afi, safi, ret);
 | |
| 			else
 | |
| 				found = true;
 | |
| 		}
 | |
| 
 | |
| 		if (!found)
 | |
| 			vty_out(vty,
 | |
| 				"%% BGP: No %s peer belonging to peer-group %s is configured\n",
 | |
| 				get_afi_safi_str(afi, safi, false), arg);
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	/* Clear all external (eBGP) neighbors. */
 | |
| 	if (sort == clear_external) {
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			if (peer->sort == BGP_PEER_IBGP)
 | |
| 				continue;
 | |
| 
 | |
| 			bgp_peer_gr_flags_update(peer);
 | |
| 
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
 | |
| 				gr_router_detected = true;
 | |
| 
 | |
| 			ret = bgp_peer_clear(peer, afi, safi, &nnode, stype);
 | |
| 
 | |
| 			if (ret < 0)
 | |
| 				bgp_clear_vty_error(vty, peer, afi, safi, ret);
 | |
| 			else
 | |
| 				found = true;
 | |
| 		}
 | |
| 
 | |
| 		if (gr_router_detected
 | |
| 		    && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, false);
 | |
| 		} else if (!gr_router_detected
 | |
| 			   && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, true);
 | |
| 		}
 | |
| 
 | |
| 		if (!found)
 | |
| 			vty_out(vty,
 | |
| 				"%% BGP: No external %s peer is configured\n",
 | |
| 				get_afi_safi_str(afi, safi, false));
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	/* Clear all neighbors belonging to a specific AS. */
 | |
| 	if (sort == clear_as) {
 | |
| 		as_t as;
 | |
| 
 | |
| 		if (!asn_str2asn(arg, &as)) {
 | |
| 			vty_out(vty, "%% BGP: No such AS %s\n", arg);
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			if (peer->as != as)
 | |
| 				continue;
 | |
| 
 | |
| 			bgp_peer_gr_flags_update(peer);
 | |
| 
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
 | |
| 				gr_router_detected = true;
 | |
| 
 | |
| 			ret = bgp_peer_clear(peer, afi, safi, &nnode, stype);
 | |
| 
 | |
| 			if (ret < 0)
 | |
| 				bgp_clear_vty_error(vty, peer, afi, safi, ret);
 | |
| 			else
 | |
| 				found = true;
 | |
| 		}
 | |
| 
 | |
| 		if (gr_router_detected
 | |
| 		    && bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, false);
 | |
| 		} else if (!gr_router_detected
 | |
| 			   && bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
 | |
| 			bgp_zebra_send_capabilities(bgp, true);
 | |
| 		}
 | |
| 
 | |
| 		if (!found)
 | |
| 			vty_out(vty,
 | |
| 				"%% BGP: No %s peer is configured with AS %s\n",
 | |
| 				get_afi_safi_str(afi, safi, false), arg);
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_clear_vty(struct vty *vty, const char *name, afi_t afi,
 | |
| 			 safi_t safi, enum clear_sort sort,
 | |
| 			 enum bgp_clear_type stype, const char *arg)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	/* BGP structure lookup. */
 | |
| 	if (name) {
 | |
| 		bgp = bgp_lookup_by_name(name);
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "Can't find BGP instance %s\n", name);
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	} else {
 | |
| 		bgp = bgp_get_default();
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "No BGP process is configured\n");
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return bgp_clear(vty, bgp, afi, safi, sort, stype, arg);
 | |
| }
 | |
| 
 | |
| /* clear soft inbound */
 | |
| static void bgp_clear_star_soft_in(struct vty *vty, const char *name)
 | |
| {
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	FOREACH_AFI_SAFI (afi, safi)
 | |
| 		bgp_clear_vty(vty, name, afi, safi, clear_all,
 | |
| 			      BGP_CLEAR_SOFT_IN, NULL);
 | |
| }
 | |
| 
 | |
| /* clear soft outbound */
 | |
| static void bgp_clear_star_soft_out(struct vty *vty, const char *name)
 | |
| {
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	FOREACH_AFI_SAFI (afi, safi)
 | |
| 		bgp_clear_vty(vty, name, afi, safi, clear_all,
 | |
| 			      BGP_CLEAR_SOFT_OUT, NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
 | |
| {
 | |
| 	bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
 | |
| }
 | |
| 
 | |
| static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
 | |
| 				uint64_t flag, int set)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/*
 | |
| 	 * If 'neighbor <interface>', then this is for directly connected peers,
 | |
| 	 * we should not accept disable-connected-check.
 | |
| 	 */
 | |
| 	if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
 | |
| 		vty_out(vty,
 | |
| 			"%s is directly connected peer, cannot accept disable-connected-check\n",
 | |
| 			ip_str);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (!set && flag == PEER_FLAG_SHUTDOWN)
 | |
| 		peer_tx_shutdown_message_unset(peer);
 | |
| 
 | |
| 	if (set)
 | |
| 		ret = peer_flag_set(peer, flag);
 | |
| 	else
 | |
| 		ret = peer_flag_unset(peer, flag);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
 | |
| {
 | |
| 	return peer_flag_modify_vty(vty, ip_str, flag, 1);
 | |
| }
 | |
| 
 | |
| static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
 | |
| 			       uint64_t flag)
 | |
| {
 | |
| 	return peer_flag_modify_vty(vty, ip_str, flag, 0);
 | |
| }
 | |
| 
 | |
| #include "bgpd/bgp_vty_clippy.c"
 | |
| 
 | |
| DEFUN_HIDDEN (bgp_local_mac,
 | |
|               bgp_local_mac_cmd,
 | |
|               "bgp local-mac vni " CMD_VNI_RANGE " mac WORD seq (0-4294967295)",
 | |
|               BGP_STR
 | |
|               "Local MAC config\n"
 | |
|               "VxLAN Network Identifier\n"
 | |
|               "VNI number\n"
 | |
|               "local mac\n"
 | |
|               "mac address\n"
 | |
|               "mac-mobility sequence\n"
 | |
|               "seq number\n")
 | |
| {
 | |
| 	int rv;
 | |
| 	vni_t vni;
 | |
| 	struct ethaddr mac;
 | |
| 	struct ipaddr ip;
 | |
| 	uint32_t seq;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	vni = strtoul(argv[3]->arg, NULL, 10);
 | |
| 	if (!prefix_str2mac(argv[5]->arg, &mac)) {
 | |
| 		vty_out(vty, "%% Malformed MAC address\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 	memset(&ip, 0, sizeof(ip));
 | |
| 	seq = strtoul(argv[7]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 	if (!bgp) {
 | |
| 		vty_out(vty, "Default BGP instance is not there\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	rv = bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, 0 /* flags */, seq,
 | |
| 			zero_esi);
 | |
| 	if (rv < 0) {
 | |
| 		vty_out(vty, "Internal error\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_HIDDEN (no_bgp_local_mac,
 | |
|               no_bgp_local_mac_cmd,
 | |
|               "no bgp local-mac vni " CMD_VNI_RANGE " mac WORD",
 | |
|               NO_STR
 | |
|               BGP_STR
 | |
|               "Local MAC config\n"
 | |
|               "VxLAN Network Identifier\n"
 | |
|               "VNI number\n"
 | |
|               "local mac\n"
 | |
|               "mac address\n")
 | |
| {
 | |
| 	int rv;
 | |
| 	vni_t vni;
 | |
| 	struct ethaddr mac;
 | |
| 	struct ipaddr ip;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	vni = strtoul(argv[4]->arg, NULL, 10);
 | |
| 	if (!prefix_str2mac(argv[6]->arg, &mac)) {
 | |
| 		vty_out(vty, "%% Malformed MAC address\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 	memset(&ip, 0, sizeof(ip));
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 	if (!bgp) {
 | |
| 		vty_out(vty, "Default BGP instance is not there\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, ZEBRA_NEIGH_ACTIVE);
 | |
| 	if (rv < 0) {
 | |
| 		vty_out(vty, "Internal error\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_synchronization,
 | |
|        no_synchronization_cmd,
 | |
|        "no synchronization",
 | |
|        NO_STR
 | |
|        "Perform IGP synchronization\n")
 | |
| {
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_auto_summary,
 | |
|        no_auto_summary_cmd,
 | |
|        "no auto-summary",
 | |
|        NO_STR
 | |
|        "Enable automatic network number summarization\n")
 | |
| {
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "router bgp" commands. */
 | |
| DEFUN_NOSH (router_bgp,
 | |
|        router_bgp_cmd,
 | |
|        "router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
 | |
|        ROUTER_STR
 | |
|        BGP_STR
 | |
|        AS_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        "Force the AS notation output\n"
 | |
|        "use 'AA.BB' format for AS 4 byte values\n"
 | |
|        "use 'AA.BB' format for all AS values\n"
 | |
|        "use plain format for all AS values\n")
 | |
| {
 | |
| 	int idx_asn = 2;
 | |
| 	int idx_view_vrf = 3;
 | |
| 	int idx_vrf = 4;
 | |
| 	int is_new_bgp = 0;
 | |
| 	int idx_asnotation = 3;
 | |
| 	int idx_asnotation_kind = 4;
 | |
| 	enum asnotation_mode asnotation = ASNOTATION_UNDEFINED;
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 	struct bgp *bgp;
 | |
| 	const char *name = NULL;
 | |
| 	enum bgp_instance_type inst_type;
 | |
| 
 | |
| 	// "router bgp" without an ASN
 | |
| 	if (argc == 2) {
 | |
| 		// Pending: Make VRF option available for ASN less config
 | |
| 		bgp = bgp_get_default();
 | |
| 
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "%% No BGP process is configured\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (listcount(bm->bgp) > 1) {
 | |
| 			vty_out(vty, "%% Please specify ASN and VRF\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// "router bgp X"
 | |
| 	else {
 | |
| 		if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
 | |
| 			vty_out(vty, "%% BGP: No such AS %s\n",
 | |
| 				argv[idx_asn]->arg);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (as == BGP_PRIVATE_AS_MAX || as == BGP_AS4_MAX)
 | |
| 			vty_out(vty, "Reserved AS used (%u|%u); AS is %u\n",
 | |
| 				BGP_PRIVATE_AS_MAX, BGP_AS4_MAX, as);
 | |
| 
 | |
| 		inst_type = BGP_INSTANCE_TYPE_DEFAULT;
 | |
| 
 | |
| 		if (argv_find(argv, argc, "VIEWVRFNAME", &idx_vrf)) {
 | |
| 			idx_view_vrf = idx_vrf - 1;
 | |
| 			if (argv[idx_view_vrf]->text) {
 | |
| 				name = argv[idx_vrf]->arg;
 | |
| 
 | |
| 				if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
 | |
| 					if (strmatch(name, VRF_DEFAULT_NAME))
 | |
| 						name = NULL;
 | |
| 					else
 | |
| 						inst_type =
 | |
| 							BGP_INSTANCE_TYPE_VRF;
 | |
| 				} else if (!strcmp(argv[idx_view_vrf]->text,
 | |
| 						   "view"))
 | |
| 					inst_type = BGP_INSTANCE_TYPE_VIEW;
 | |
| 			}
 | |
| 		}
 | |
| 		if (argv_find(argv, argc, "as-notation", &idx_asnotation)) {
 | |
| 			idx_asnotation_kind = idx_asnotation + 1;
 | |
| 			if (strmatch(argv[idx_asnotation_kind]->text, "dot+"))
 | |
| 				asnotation = ASNOTATION_DOTPLUS;
 | |
| 			else if (strmatch(argv[idx_asnotation_kind]->text,
 | |
| 					  "dot"))
 | |
| 				asnotation = ASNOTATION_DOT;
 | |
| 			else if (strmatch(argv[idx_asnotation_kind]->text,
 | |
| 					  "plain"))
 | |
| 				asnotation = ASNOTATION_PLAIN;
 | |
| 		}
 | |
| 
 | |
| 		if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 			is_new_bgp = (bgp_lookup(as, name) == NULL);
 | |
| 
 | |
| 		ret = bgp_get_vty(&bgp, &as, name, inst_type,
 | |
| 				  argv[idx_asn]->arg, asnotation);
 | |
| 		switch (ret) {
 | |
| 		case BGP_ERR_AS_MISMATCH:
 | |
| 			vty_out(vty, "BGP is already running; AS is %s\n",
 | |
| 				bgp->as_pretty);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		case BGP_ERR_INSTANCE_MISMATCH:
 | |
| 			vty_out(vty,
 | |
| 				"BGP instance name and AS number mismatch\n");
 | |
| 			vty_out(vty,
 | |
| 				"BGP instance is already running; AS is %s\n",
 | |
| 				bgp->as_pretty);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * If we just instantiated the default instance, complete
 | |
| 		 * any pending VRF-VPN leaking that was configured via
 | |
| 		 * earlier "router bgp X vrf FOO" blocks.
 | |
| 		 */
 | |
| 		if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 			vpn_leak_postchange_all();
 | |
| 
 | |
| 		if (inst_type == BGP_INSTANCE_TYPE_VRF)
 | |
| 			bgp_vpn_leak_export(bgp);
 | |
| 		/* Pending: handle when user tries to change a view to vrf n vv.
 | |
| 		 */
 | |
| 		/* for pre-existing bgp instance,
 | |
| 		 * - update as_pretty
 | |
| 		 * - update asnotation if explicitly mentioned
 | |
| 		 */
 | |
| 		if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
 | |
| 			XFREE(MTYPE_BGP, bgp->as_pretty);
 | |
| 			bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg);
 | |
| 			if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) &&
 | |
| 			    asnotation != ASNOTATION_UNDEFINED) {
 | |
| 				SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
 | |
| 				bgp->asnotation = asnotation;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* unset the auto created flag as the user config is now present */
 | |
| 	UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
 | |
| 	VTY_PUSH_CONTEXT(BGP_NODE, bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "no router bgp" commands. */
 | |
| DEFUN (no_router_bgp,
 | |
|        no_router_bgp_cmd,
 | |
|        "no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
 | |
|        NO_STR
 | |
|        ROUTER_STR
 | |
|        BGP_STR
 | |
|        AS_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        "Force the AS notation output\n"
 | |
|        "use 'AA.BB' format for AS 4 byte values\n"
 | |
|        "use 'AA.BB' format for all AS values\n"
 | |
|        "use plain format for all AS values\n")
 | |
| {
 | |
| 	int idx_asn = 3;
 | |
| 	int idx_vrf = 5;
 | |
| 	as_t as;
 | |
| 	struct bgp *bgp;
 | |
| 	const char *name = NULL;
 | |
| 
 | |
| 	// "no router bgp" without an ASN
 | |
| 	if (argc == 3) {
 | |
| 		// Pending: Make VRF option available for ASN less config
 | |
| 		bgp = bgp_get_default();
 | |
| 
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "%% No BGP process is configured\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (listcount(bm->bgp) > 1) {
 | |
| 			vty_out(vty, "%% Please specify ASN and VRF\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (bgp->l3vni) {
 | |
| 			vty_out(vty, "%% Please unconfigure l3vni %u\n",
 | |
| 				bgp->l3vni);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
 | |
| 			vty_out(vty, "%% BGP: No such AS %s\n",
 | |
| 				argv[idx_asn]->arg);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		if (argc > 4) {
 | |
| 			name = argv[idx_vrf]->arg;
 | |
| 			if (strmatch(argv[idx_vrf - 1]->text, "vrf")
 | |
| 			    && strmatch(name, VRF_DEFAULT_NAME))
 | |
| 				name = NULL;
 | |
| 		}
 | |
| 
 | |
| 		/* Lookup bgp structure. */
 | |
| 		bgp = bgp_lookup(as, name);
 | |
| 		if (!bgp) {
 | |
| 			vty_out(vty, "%% Can't find BGP instance\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (bgp->l3vni) {
 | |
| 			vty_out(vty, "%% Please unconfigure l3vni %u\n",
 | |
| 				bgp->l3vni);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		/* Cannot delete default instance if vrf instances exist */
 | |
| 		if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
 | |
| 			struct listnode *node;
 | |
| 			struct bgp *tmp_bgp;
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) {
 | |
| 				if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
 | |
| 					continue;
 | |
| 				if (CHECK_FLAG(
 | |
| 					    tmp_bgp->af_flags[AFI_IP]
 | |
| 							     [SAFI_UNICAST],
 | |
| 					    BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
 | |
| 				    CHECK_FLAG(
 | |
| 					    tmp_bgp->af_flags[AFI_IP6]
 | |
| 							     [SAFI_UNICAST],
 | |
| 					    BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
 | |
| 				    CHECK_FLAG(
 | |
| 					    tmp_bgp->af_flags[AFI_IP]
 | |
| 							     [SAFI_UNICAST],
 | |
| 					    BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
 | |
| 				    CHECK_FLAG(
 | |
| 					    tmp_bgp->af_flags[AFI_IP6]
 | |
| 							     [SAFI_UNICAST],
 | |
| 					    BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
 | |
| 				    CHECK_FLAG(tmp_bgp->af_flags[AFI_IP]
 | |
| 								[SAFI_UNICAST],
 | |
| 					       BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
 | |
| 				    CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6]
 | |
| 								[SAFI_UNICAST],
 | |
| 					       BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
 | |
| 				    (bgp == bgp_get_evpn() &&
 | |
| 				     (CHECK_FLAG(
 | |
| 					      tmp_bgp->af_flags[AFI_L2VPN]
 | |
| 							       [SAFI_EVPN],
 | |
| 					      BGP_L2VPN_EVPN_ADV_IPV4_UNICAST) ||
 | |
| 				      CHECK_FLAG(
 | |
| 					      tmp_bgp->af_flags[AFI_L2VPN]
 | |
| 							       [SAFI_EVPN],
 | |
| 					      BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP) ||
 | |
| 				      CHECK_FLAG(
 | |
| 					      tmp_bgp->af_flags[AFI_L2VPN]
 | |
| 							       [SAFI_EVPN],
 | |
| 					      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST) ||
 | |
| 				      CHECK_FLAG(
 | |
| 					      tmp_bgp->af_flags[AFI_L2VPN]
 | |
| 							       [SAFI_EVPN],
 | |
| 					      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) ||
 | |
| 				    (tmp_bgp->l3vni)) {
 | |
| 					vty_out(vty,
 | |
| 						"%% Cannot delete default BGP instance. Dependent VRF instances exist\n");
 | |
| 					return CMD_WARNING_CONFIG_FAILED;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	bgp_delete(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* bgp session-dscp */
 | |
| 
 | |
| DEFPY (bgp_session_dscp,
 | |
|        bgp_session_dscp_cmd,
 | |
|        "bgp session-dscp (0-63)$dscp",
 | |
|        BGP_STR
 | |
|        "Override default (C6) bgp TCP session DSCP value\n"
 | |
|        "Manually configured dscp parameter\n")
 | |
| {
 | |
| 	bm->tcp_dscp = dscp << 2;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_session_dscp,
 | |
|        no_bgp_session_dscp_cmd,
 | |
|        "no bgp session-dscp [(0-63)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Override default (C6) bgp TCP session DSCP value\n"
 | |
|        "Manually configured dscp parameter\n")
 | |
| {
 | |
| 	bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* BGP router-id.  */
 | |
| 
 | |
| DEFPY (bgp_router_id,
 | |
|        bgp_router_id_cmd,
 | |
|        "bgp router-id A.B.C.D",
 | |
|        BGP_STR
 | |
|        "Override configured router identifier\n"
 | |
|        "Manually configured router identifier\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_router_id_static_set(bgp, router_id);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_router_id,
 | |
|        no_bgp_router_id_cmd,
 | |
|        "no bgp router-id [A.B.C.D]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Override configured router identifier\n"
 | |
|        "Manually configured router identifier\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (router_id_str) {
 | |
| 		if (!IPV4_ADDR_SAME(&bgp->router_id_static, &router_id)) {
 | |
| 			vty_out(vty, "%% BGP router-id doesn't match\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	router_id.s_addr = 0;
 | |
| 	bgp_router_id_static_set(bgp, router_id);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_community_alias, bgp_community_alias_cmd,
 | |
|       "[no$no] bgp community alias WORD$community ALIAS_NAME$alias_name",
 | |
|       NO_STR BGP_STR
 | |
|       "Add community specific parameters\n"
 | |
|       "Create an alias for a community\n"
 | |
|       "Community (AA:BB or AA:BB:CC)\n"
 | |
|       "Alias name\n")
 | |
| {
 | |
| 	struct community_alias ca = {};
 | |
| 	struct community_alias *lookup_community;
 | |
| 	struct community_alias *lookup_alias;
 | |
| 	struct community *comm;
 | |
| 	struct lcommunity *lcomm;
 | |
| 	uint8_t invalid = 0;
 | |
| 
 | |
| 	comm = community_str2com(community);
 | |
| 	if (!comm)
 | |
| 		invalid++;
 | |
| 	community_free(&comm);
 | |
| 
 | |
| 	lcomm = lcommunity_str2com(community);
 | |
| 	if (!lcomm)
 | |
| 		invalid++;
 | |
| 	lcommunity_free(&lcomm);
 | |
| 
 | |
| 	if (invalid > 1) {
 | |
| 		vty_out(vty, "Invalid community format\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	strlcpy(ca.community, community, sizeof(ca.community));
 | |
| 	strlcpy(ca.alias, alias_name, sizeof(ca.alias));
 | |
| 
 | |
| 	lookup_community = bgp_ca_community_lookup(&ca);
 | |
| 	lookup_alias = bgp_ca_alias_lookup(&ca);
 | |
| 
 | |
| 	if (no) {
 | |
| 		bgp_ca_alias_delete(&ca);
 | |
| 		bgp_ca_community_delete(&ca);
 | |
| 	} else {
 | |
| 		if (lookup_alias) {
 | |
| 			/* Lookup if community hash table has an item
 | |
| 			 * with the same alias name.
 | |
| 			 */
 | |
| 			strlcpy(ca.community, lookup_alias->community,
 | |
| 				sizeof(ca.community));
 | |
| 			if (bgp_ca_community_lookup(&ca)) {
 | |
| 				vty_out(vty,
 | |
| 					"community (%s) already has this alias (%s)\n",
 | |
| 					lookup_alias->community,
 | |
| 					lookup_alias->alias);
 | |
| 				return CMD_WARNING;
 | |
| 			}
 | |
| 			bgp_ca_alias_delete(&ca);
 | |
| 		}
 | |
| 
 | |
| 		if (lookup_community) {
 | |
| 			/* Lookup if alias hash table has an item
 | |
| 			 * with the same community.
 | |
| 			 */
 | |
| 			strlcpy(ca.alias, lookup_community->alias,
 | |
| 				sizeof(ca.alias));
 | |
| 			if (bgp_ca_alias_lookup(&ca)) {
 | |
| 				vty_out(vty,
 | |
| 					"alias (%s) already has this community (%s)\n",
 | |
| 					lookup_community->alias,
 | |
| 					lookup_community->community);
 | |
| 				return CMD_WARNING;
 | |
| 			}
 | |
| 			bgp_ca_community_delete(&ca);
 | |
| 		}
 | |
| 
 | |
| 		bgp_ca_alias_insert(&ca);
 | |
| 		bgp_ca_community_insert(&ca);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_global_suppress_fib_pending,
 | |
|        bgp_global_suppress_fib_pending_cmd,
 | |
|        "[no] bgp suppress-fib-pending",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Advertise only routes that are programmed in kernel to peers globally\n")
 | |
| {
 | |
| 	bm_wait_for_fib_set(!no);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_suppress_fib_pending,
 | |
|        bgp_suppress_fib_pending_cmd,
 | |
|        "[no] bgp suppress-fib-pending",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Advertise only routes that are programmed in kernel to peers\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp_suppress_fib_pending_set(bgp, !no);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* BGP Cluster ID.  */
 | |
| DEFUN (bgp_cluster_id,
 | |
|        bgp_cluster_id_cmd,
 | |
|        "bgp cluster-id <A.B.C.D|(1-4294967295)>",
 | |
|        BGP_STR
 | |
|        "Configure Route-Reflector Cluster-id\n"
 | |
|        "Route-Reflector Cluster-id in IP address format\n"
 | |
|        "Route-Reflector Cluster-id as 32 bit quantity\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ipv4 = 2;
 | |
| 	int ret;
 | |
| 	struct in_addr cluster;
 | |
| 
 | |
| 	ret = inet_aton(argv[idx_ipv4]->arg, &cluster);
 | |
| 	if (!ret) {
 | |
| 		vty_out(vty, "%% Malformed bgp cluster identifier\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_cluster_id_set(bgp, &cluster);
 | |
| 	bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_cluster_id,
 | |
|        no_bgp_cluster_id_cmd,
 | |
|        "no bgp cluster-id [<A.B.C.D|(1-4294967295)>]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure Route-Reflector Cluster-id\n"
 | |
|        "Route-Reflector Cluster-id in IP address format\n"
 | |
|        "Route-Reflector Cluster-id as 32 bit quantity\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_cluster_id_unset(bgp);
 | |
| 	bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_norib,
 | |
|        bgp_norib_cmd,
 | |
|        "bgp no-rib",
 | |
|        BGP_STR
 | |
|        "Disable BGP route installation to RIB (Zebra)\n")
 | |
| {
 | |
| 	if (bgp_option_check(BGP_OPT_NO_FIB)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% No-RIB option is already set, nothing to do here.\n");
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	bgp_option_norib_set_runtime();
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_norib,
 | |
|        no_bgp_norib_cmd,
 | |
|        "no bgp no-rib",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Disable BGP route installation to RIB (Zebra)\n")
 | |
| {
 | |
| 	if (!bgp_option_check(BGP_OPT_NO_FIB)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% No-RIB option is not set, nothing to do here.\n");
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	bgp_option_norib_unset_runtime();
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_send_extra_data,
 | |
|        no_bgp_send_extra_data_cmd,
 | |
|        "[no] bgp send-extra-data zebra",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Extra data to Zebra for display/use\n"
 | |
|        "To zebra\n")
 | |
| {
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA);
 | |
| 	else
 | |
| 		SET_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_confederation_identifier,
 | |
|        bgp_confederation_identifier_cmd,
 | |
|        "bgp confederation identifier ASNUM",
 | |
|        BGP_STR
 | |
|        "AS confederation parameters\n"
 | |
|        AS_STR
 | |
|        "Set routing domain confederation AS\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	as_t as;
 | |
| 
 | |
| 	if (!asn_str2asn(argv[idx_number]->arg, &as)) {
 | |
| 		vty_out(vty, "%% BGP: No such AS %s\n", argv[idx_number]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_confederation_id_set(bgp, as, argv[idx_number]->arg);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_confederation_identifier,
 | |
|        no_bgp_confederation_identifier_cmd,
 | |
|        "no bgp confederation identifier [ASNUM]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "AS confederation parameters\n"
 | |
|        AS_STR
 | |
|        "Set routing domain confederation AS\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_confederation_id_unset(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_confederation_peers,
 | |
|        bgp_confederation_peers_cmd,
 | |
|        "bgp confederation peers ASNUM...",
 | |
|        BGP_STR
 | |
|        "AS confederation parameters\n"
 | |
|        "Peer ASs in BGP confederation\n"
 | |
|        AS_STR)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_asn = 3;
 | |
| 	as_t as;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = idx_asn; i < argc; i++) {
 | |
| 		if (!asn_str2asn(argv[i]->arg, &as)) {
 | |
| 			vty_out(vty, "%% Invalid confed peer AS value: %s\n",
 | |
| 				argv[i]->arg);
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		bgp_confederation_peers_add(bgp, as, argv[i]->arg);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_confederation_peers,
 | |
|        no_bgp_confederation_peers_cmd,
 | |
|        "no bgp confederation peers ASNUM...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "AS confederation parameters\n"
 | |
|        "Peer ASs in BGP confederation\n"
 | |
|        AS_STR)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_asn = 4;
 | |
| 	as_t as;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = idx_asn; i < argc; i++) {
 | |
| 		if (!asn_str2asn(argv[i]->arg, &as)) {
 | |
| 			vty_out(vty, "%% Invalid confed peer AS value: %s\n",
 | |
| 				argv[i]->arg);
 | |
| 			continue;
 | |
| 		}
 | |
| 		bgp_confederation_peers_remove(bgp, as);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Central routine for maximum-paths configuration.
 | |
|  * @peer_type: BGP_PEER_EBGP or BGP_PEER_IBGP
 | |
|  * @set: 1 for setting values, 0 for removing the max-paths config.
 | |
|  */
 | |
| static int bgp_maxpaths_config_vty(struct vty *vty, int peer_type,
 | |
| 				   const char *mpaths, uint16_t options,
 | |
| 				   int set)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	uint16_t maxpaths = 0;
 | |
| 	int ret;
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	afi = bgp_node_afi(vty);
 | |
| 	safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	if (set) {
 | |
| 		maxpaths = strtol(mpaths, NULL, 10);
 | |
| 		if (maxpaths > multipath_num) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Maxpaths Specified: %d is > than multipath num specified on bgp command line %d",
 | |
| 				maxpaths, multipath_num);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		ret = bgp_maximum_paths_set(bgp, afi, safi, peer_type, maxpaths,
 | |
| 					    options);
 | |
| 	} else
 | |
| 		ret = bgp_maximum_paths_unset(bgp, afi, safi, peer_type);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Failed to %sset maximum-paths %s %u for afi %u, safi %u\n",
 | |
| 			(set == 1) ? "" : "un",
 | |
| 			(peer_type == BGP_PEER_EBGP) ? "ebgp" : "ibgp",
 | |
| 			maxpaths, afi, safi);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_maxmed_admin,
 | |
|        bgp_maxmed_admin_cmd,
 | |
|        "bgp max-med administrative ",
 | |
|        BGP_STR
 | |
|        "Advertise routes with max-med\n"
 | |
|        "Administratively applied, for an indefinite period\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->v_maxmed_admin = 1;
 | |
| 	bgp->maxmed_admin_value = BGP_MAXMED_VALUE_DEFAULT;
 | |
| 
 | |
| 	bgp_maxmed_update(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_maxmed_admin_medv,
 | |
|        bgp_maxmed_admin_medv_cmd,
 | |
|        "bgp max-med administrative (0-4294967295)",
 | |
|        BGP_STR
 | |
|        "Advertise routes with max-med\n"
 | |
|        "Administratively applied, for an indefinite period\n"
 | |
|        "Max MED value to be used\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 
 | |
| 	bgp->v_maxmed_admin = 1;
 | |
| 	bgp->maxmed_admin_value = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp_maxmed_update(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_maxmed_admin,
 | |
|        no_bgp_maxmed_admin_cmd,
 | |
|        "no bgp max-med administrative [(0-4294967295)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Advertise routes with max-med\n"
 | |
|        "Administratively applied, for an indefinite period\n"
 | |
|        "Max MED value to be used\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp->v_maxmed_admin = BGP_MAXMED_ADMIN_UNCONFIGURED;
 | |
| 	bgp->maxmed_admin_value = BGP_MAXMED_VALUE_DEFAULT;
 | |
| 	bgp_maxmed_update(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_maxmed_onstartup,
 | |
|        bgp_maxmed_onstartup_cmd,
 | |
|        "bgp max-med on-startup (5-86400) [(0-4294967295)]",
 | |
|        BGP_STR
 | |
|        "Advertise routes with max-med\n"
 | |
|        "Effective on a startup\n"
 | |
|        "Time (seconds) period for max-med\n"
 | |
|        "Max MED value to be used\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(5-86400)", &idx))
 | |
| 		bgp->v_maxmed_onstartup = strtoul(argv[idx]->arg, NULL, 10);
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		bgp->maxmed_onstartup_value = strtoul(argv[idx]->arg, NULL, 10);
 | |
| 	else
 | |
| 		bgp->maxmed_onstartup_value = BGP_MAXMED_VALUE_DEFAULT;
 | |
| 
 | |
| 	bgp_maxmed_update(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_maxmed_onstartup,
 | |
|        no_bgp_maxmed_onstartup_cmd,
 | |
|        "no bgp max-med on-startup [(5-86400) [(0-4294967295)]]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Advertise routes with max-med\n"
 | |
|        "Effective on a startup\n"
 | |
|        "Time (seconds) period for max-med\n"
 | |
|        "Max MED value to be used\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* Cancel max-med onstartup if its on */
 | |
| 	if (bgp->t_maxmed_onstartup) {
 | |
| 		EVENT_OFF(bgp->t_maxmed_onstartup);
 | |
| 		bgp->maxmed_onstartup_over = 1;
 | |
| 	}
 | |
| 
 | |
| 	bgp->v_maxmed_onstartup = BGP_MAXMED_ONSTARTUP_UNCONFIGURED;
 | |
| 	bgp->maxmed_onstartup_value = BGP_MAXMED_VALUE_DEFAULT;
 | |
| 
 | |
| 	bgp_maxmed_update(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_global_update_delay_config_vty(struct vty *vty,
 | |
| 					      uint16_t update_delay,
 | |
| 					      uint16_t establish_wait)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 	bool vrf_cfg = false;
 | |
| 
 | |
| 	/*
 | |
| 	 * See if update-delay is set per-vrf and warn user to delete it
 | |
| 	 * Note that we only need to check this if this is the first time
 | |
| 	 * setting the global config.
 | |
| 	 */
 | |
| 	if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) {
 | |
| 		for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 			if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
 | |
| 				vty_out(vty,
 | |
| 					"%% update-delay configuration found in vrf %s\n",
 | |
| 					bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
 | |
| 						? VRF_DEFAULT_NAME
 | |
| 						: bgp->name);
 | |
| 				vrf_cfg = true;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (vrf_cfg) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: global update-delay config not permitted\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	if (!establish_wait) { /* update-delay <delay> */
 | |
| 		bm->v_update_delay = update_delay;
 | |
| 		bm->v_establish_wait = bm->v_update_delay;
 | |
| 	} else {
 | |
| 		/* update-delay <delay> <establish-wait> */
 | |
| 		if (update_delay < establish_wait) {
 | |
| 			vty_out(vty,
 | |
| 				"%%Failed: update-delay less than the establish-wait!\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		bm->v_update_delay = update_delay;
 | |
| 		bm->v_establish_wait = establish_wait;
 | |
| 	}
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		bgp->v_update_delay = bm->v_update_delay;
 | |
| 		bgp->v_establish_wait = bm->v_establish_wait;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_global_update_delay_deconfig_vty(struct vty *vty)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	bm->v_update_delay = BGP_UPDATE_DELAY_DEF;
 | |
| 	bm->v_establish_wait = bm->v_update_delay;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		bgp->v_update_delay = bm->v_update_delay;
 | |
| 		bgp->v_establish_wait = bm->v_establish_wait;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_update_delay_config_vty(struct vty *vty, uint16_t update_delay,
 | |
| 				       uint16_t establish_wait)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* if configured globally, per-instance config is not allowed */
 | |
| 	if (bm->v_update_delay) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: per-vrf update-delay config not permitted with global update-delay\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	if (!establish_wait) /* update-delay <delay> */
 | |
| 	{
 | |
| 		bgp->v_update_delay = update_delay;
 | |
| 		bgp->v_establish_wait = bgp->v_update_delay;
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	/* update-delay <delay> <establish-wait> */
 | |
| 	if (update_delay < establish_wait) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: update-delay less than the establish-wait!\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp->v_update_delay = update_delay;
 | |
| 	bgp->v_establish_wait = establish_wait;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_update_delay_deconfig_vty(struct vty *vty)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* If configured globally, cannot remove from one bgp instance */
 | |
| 	if (bm->v_update_delay) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
 | |
| 	bgp->v_establish_wait = bgp->v_update_delay;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	/* If configured globally, no need to display per-instance value */
 | |
| 	if (bgp->v_update_delay != bm->v_update_delay) {
 | |
| 		vty_out(vty, " update-delay %d", bgp->v_update_delay);
 | |
| 		if (bgp->v_update_delay != bgp->v_establish_wait)
 | |
| 			vty_out(vty, " %d", bgp->v_establish_wait);
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Global update-delay configuration */
 | |
| DEFPY (bgp_global_update_delay,
 | |
|        bgp_global_update_delay_cmd,
 | |
|        "bgp update-delay (0-3600)$delay [(1-3600)$wait]",
 | |
|        BGP_STR
 | |
|        "Force initial delay for best-path and updates for all bgp instances\n"
 | |
|        "Max delay in seconds\n"
 | |
|        "Establish wait in seconds\n")
 | |
| {
 | |
| 	return bgp_global_update_delay_config_vty(vty, delay, wait);
 | |
| }
 | |
| 
 | |
| /* Global update-delay deconfiguration */
 | |
| DEFPY (no_bgp_global_update_delay,
 | |
|        no_bgp_global_update_delay_cmd,
 | |
|        "no bgp update-delay [(0-3600) [(1-3600)]]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Force initial delay for best-path and updates\n"
 | |
|        "Max delay in seconds\n"
 | |
|        "Establish wait in seconds\n")
 | |
| {
 | |
| 	return bgp_global_update_delay_deconfig_vty(vty);
 | |
| }
 | |
| 
 | |
| /* Update-delay configuration */
 | |
| 
 | |
| DEFPY (bgp_update_delay,
 | |
|        bgp_update_delay_cmd,
 | |
|        "update-delay (0-3600)$delay [(1-3600)$wait]",
 | |
|        "Force initial delay for best-path and updates\n"
 | |
|        "Max delay in seconds\n"
 | |
|        "Establish wait in seconds\n")
 | |
| {
 | |
| 	return bgp_update_delay_config_vty(vty, delay, wait);
 | |
| }
 | |
| 
 | |
| /* Update-delay deconfiguration */
 | |
| DEFPY (no_bgp_update_delay,
 | |
|        no_bgp_update_delay_cmd,
 | |
|        "no update-delay [(0-3600) [(1-3600)]]",
 | |
|        NO_STR
 | |
|        "Force initial delay for best-path and updates\n"
 | |
|        "Max delay in seconds\n"
 | |
|        "Establish wait in seconds\n")
 | |
| {
 | |
| 	return bgp_update_delay_deconfig_vty(vty);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int bgp_wpkt_quanta_config_vty(struct vty *vty, uint32_t quanta,
 | |
| 				      bool set)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	quanta = set ? quanta : BGP_WRITE_PACKET_MAX;
 | |
| 	atomic_store_explicit(&bgp->wpkt_quanta, quanta, memory_order_relaxed);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_rpkt_quanta_config_vty(struct vty *vty, uint32_t quanta,
 | |
| 				      bool set)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	quanta = set ? quanta : BGP_READ_PACKET_MAX;
 | |
| 	atomic_store_explicit(&bgp->rpkt_quanta, quanta, memory_order_relaxed);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	uint32_t quanta =
 | |
| 		atomic_load_explicit(&bgp->wpkt_quanta, memory_order_relaxed);
 | |
| 	if (quanta != BGP_WRITE_PACKET_MAX)
 | |
| 		vty_out(vty, " write-quanta %d\n", quanta);
 | |
| }
 | |
| 
 | |
| void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	uint32_t quanta =
 | |
| 		atomic_load_explicit(&bgp->rpkt_quanta, memory_order_relaxed);
 | |
| 	if (quanta != BGP_READ_PACKET_MAX)
 | |
| 		vty_out(vty, " read-quanta %d\n", quanta);
 | |
| }
 | |
| 
 | |
| /* Packet quanta configuration
 | |
|  *
 | |
|  * XXX: The value set here controls the size of a stack buffer in the IO
 | |
|  * thread. When changing these limits be careful to prevent stack overflow.
 | |
|  *
 | |
|  * Furthermore, the maximums used here should correspond to
 | |
|  * BGP_WRITE_PACKET_MAX and BGP_READ_PACKET_MAX.
 | |
|  */
 | |
| DEFPY (bgp_wpkt_quanta,
 | |
|        bgp_wpkt_quanta_cmd,
 | |
|        "[no] write-quanta (1-64)$quanta",
 | |
|        NO_STR
 | |
|        "How many packets to write to peer socket per run\n"
 | |
|        "Number of packets\n")
 | |
| {
 | |
| 	return bgp_wpkt_quanta_config_vty(vty, quanta, !no);
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_rpkt_quanta,
 | |
|        bgp_rpkt_quanta_cmd,
 | |
|        "[no] read-quanta (1-10)$quanta",
 | |
|        NO_STR
 | |
|        "How many packets to read from peer socket per I/O cycle\n"
 | |
|        "Number of packets\n")
 | |
| {
 | |
| 	return bgp_rpkt_quanta_config_vty(vty, quanta, !no);
 | |
| }
 | |
| 
 | |
| void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	if (!bgp->heuristic_coalesce)
 | |
| 		vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
 | |
| }
 | |
| 
 | |
| /* BGP TCP keepalive */
 | |
| static void bgp_config_tcp_keepalive(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	if (bgp->tcp_keepalive_idle) {
 | |
| 		vty_out(vty, " bgp tcp-keepalive %u %u %u\n",
 | |
| 			bgp->tcp_keepalive_idle, bgp->tcp_keepalive_intvl,
 | |
| 			bgp->tcp_keepalive_probes);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_coalesce_time,
 | |
|        bgp_coalesce_time_cmd,
 | |
|        "coalesce-time (0-4294967295)",
 | |
|        "Subgroup coalesce timer\n"
 | |
|        "Subgroup coalesce timer value (in ms)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	bgp->heuristic_coalesce = false;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		bgp->coalesce_time = strtoul(argv[idx]->arg, NULL, 10);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_coalesce_time,
 | |
|        no_bgp_coalesce_time_cmd,
 | |
|        "no coalesce-time (0-4294967295)",
 | |
|        NO_STR
 | |
|        "Subgroup coalesce timer\n"
 | |
|        "Subgroup coalesce timer value (in ms)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->heuristic_coalesce = true;
 | |
| 	bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Maximum-paths configuration */
 | |
| DEFUN (bgp_maxpaths,
 | |
|        bgp_maxpaths_cmd,
 | |
|        "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM),
 | |
|        "Forward packets over multiple paths\n"
 | |
|        "Number of paths\n")
 | |
| {
 | |
| 	int idx_number = 1;
 | |
| 	return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP,
 | |
| 				       argv[idx_number]->arg, 0, 1);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_maxpaths, bgp_maxpaths_hidden_cmd,
 | |
| 	     "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM),
 | |
| 	     "Forward packets over multiple paths\n"
 | |
| 	     "Number of paths\n")
 | |
| 
 | |
| DEFUN (bgp_maxpaths_ibgp,
 | |
|        bgp_maxpaths_ibgp_cmd,
 | |
|        "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM),
 | |
|        "Forward packets over multiple paths\n"
 | |
|        "iBGP-multipath\n"
 | |
|        "Number of paths\n")
 | |
| {
 | |
| 	int idx_number = 2;
 | |
| 	return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP,
 | |
| 				       argv[idx_number]->arg, 0, 1);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_maxpaths_ibgp, bgp_maxpaths_ibgp_hidden_cmd,
 | |
| 	     "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM),
 | |
| 	     "Forward packets over multiple paths\n"
 | |
| 	     "iBGP-multipath\n"
 | |
| 	     "Number of paths\n")
 | |
| 
 | |
| DEFUN (bgp_maxpaths_ibgp_cluster,
 | |
|        bgp_maxpaths_ibgp_cluster_cmd,
 | |
|        "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM) " equal-cluster-length",
 | |
|        "Forward packets over multiple paths\n"
 | |
|        "iBGP-multipath\n"
 | |
|        "Number of paths\n"
 | |
|        "Match the cluster length\n")
 | |
| {
 | |
| 	int idx_number = 2;
 | |
| 	return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP,
 | |
| 				       argv[idx_number]->arg, true, 1);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_maxpaths_ibgp_cluster, bgp_maxpaths_ibgp_cluster_hidden_cmd,
 | |
| 	     "maximum-paths ibgp " CMD_RANGE_STR(
 | |
| 		     1, MULTIPATH_NUM) " equal-cluster-length",
 | |
| 	     "Forward packets over multiple paths\n"
 | |
| 	     "iBGP-multipath\n"
 | |
| 	     "Number of paths\n"
 | |
| 	     "Match the cluster length\n")
 | |
| 
 | |
| DEFUN (no_bgp_maxpaths,
 | |
|        no_bgp_maxpaths_cmd,
 | |
|        "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]",
 | |
|        NO_STR
 | |
|        "Forward packets over multiple paths\n"
 | |
|        "Number of paths\n")
 | |
| {
 | |
| 	return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP, NULL, 0, 0);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_bgp_maxpaths, no_bgp_maxpaths_hidden_cmd,
 | |
| 	     "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]", NO_STR
 | |
| 	     "Forward packets over multiple paths\n"
 | |
| 	     "Number of paths\n")
 | |
| 
 | |
| DEFUN (no_bgp_maxpaths_ibgp,
 | |
|        no_bgp_maxpaths_ibgp_cmd,
 | |
|        "no maximum-paths ibgp [" CMD_RANGE_STR(1, MULTIPATH_NUM) " [equal-cluster-length]]",
 | |
|        NO_STR
 | |
|        "Forward packets over multiple paths\n"
 | |
|        "iBGP-multipath\n"
 | |
|        "Number of paths\n"
 | |
|        "Match the cluster length\n")
 | |
| {
 | |
| 	return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, NULL, 0, 0);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_hidden_cmd,
 | |
| 	     "no maximum-paths ibgp [" CMD_RANGE_STR(
 | |
| 		     1, MULTIPATH_NUM) " [equal-cluster-length]]",
 | |
| 	     NO_STR
 | |
| 	     "Forward packets over multiple paths\n"
 | |
| 	     "iBGP-multipath\n"
 | |
| 	     "Number of paths\n"
 | |
| 	     "Match the cluster length\n")
 | |
| 
 | |
| static void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp,
 | |
| 				      afi_t afi, safi_t safi)
 | |
| {
 | |
| 	if (bgp->maxpaths[afi][safi].maxpaths_ebgp != multipath_num) {
 | |
| 		vty_out(vty, "  maximum-paths %d\n",
 | |
| 			bgp->maxpaths[afi][safi].maxpaths_ebgp);
 | |
| 	}
 | |
| 
 | |
| 	if (bgp->maxpaths[afi][safi].maxpaths_ibgp != multipath_num) {
 | |
| 		vty_out(vty, "  maximum-paths ibgp %d",
 | |
| 			bgp->maxpaths[afi][safi].maxpaths_ibgp);
 | |
| 		if (bgp->maxpaths[afi][safi].same_clusterlen)
 | |
| 			vty_out(vty, " equal-cluster-length");
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* BGP timers.  */
 | |
| 
 | |
| DEFUN (bgp_timers,
 | |
|        bgp_timers_cmd,
 | |
|        "timers bgp (0-65535) (0-65535)",
 | |
|        "Adjust routing timers\n"
 | |
|        "BGP timers\n"
 | |
|        "Keepalive interval\n"
 | |
|        "Holdtime\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 2;
 | |
| 	int idx_number_2 = 3;
 | |
| 	unsigned long keepalive = 0;
 | |
| 	unsigned long holdtime = 0;
 | |
| 
 | |
| 	keepalive = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	holdtime = strtoul(argv[idx_number_2]->arg, NULL, 10);
 | |
| 
 | |
| 	/* Holdtime value check. */
 | |
| 	if (holdtime < 3 && holdtime != 0) {
 | |
| 		vty_out(vty,
 | |
| 			"%% hold time value must be either 0 or greater than 3\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY,
 | |
| 		       BGP_DEFAULT_DELAYOPEN);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_timers,
 | |
|        no_bgp_timers_cmd,
 | |
|        "no timers bgp [(0-65535) (0-65535)]",
 | |
|        NO_STR
 | |
|        "Adjust routing timers\n"
 | |
|        "BGP timers\n"
 | |
|        "Keepalive interval\n"
 | |
|        "Holdtime\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_timers_set(bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
 | |
| 		       DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* BGP minimum holdtime.  */
 | |
| 
 | |
| DEFUN(bgp_minimum_holdtime, bgp_minimum_holdtime_cmd,
 | |
|       "bgp minimum-holdtime (1-65535)",
 | |
|       "BGP specific commands\n"
 | |
|       "BGP minimum holdtime\n"
 | |
|       "Seconds\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 2;
 | |
| 	unsigned long min_holdtime;
 | |
| 
 | |
| 	min_holdtime = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp->default_min_holdtime = min_holdtime;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_minimum_holdtime, no_bgp_minimum_holdtime_cmd,
 | |
|       "no bgp minimum-holdtime [(1-65535)]",
 | |
|       NO_STR
 | |
|       "BGP specific commands\n"
 | |
|       "BGP minimum holdtime\n"
 | |
|       "Seconds\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->default_min_holdtime = 0;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_tcp_keepalive, bgp_tcp_keepalive_cmd,
 | |
|       "bgp tcp-keepalive (1-65535)$idle (1-65535)$intvl (1-30)$probes",
 | |
|       BGP_STR
 | |
|       "TCP keepalive parameters\n"
 | |
|       "TCP keepalive idle time (seconds)\n"
 | |
|       "TCP keepalive interval (seconds)\n"
 | |
|       "TCP keepalive maximum probes\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp_tcp_keepalive_set(bgp, (uint16_t)idle, (uint16_t)intvl,
 | |
| 			      (uint16_t)probes);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(no_bgp_tcp_keepalive, no_bgp_tcp_keepalive_cmd,
 | |
|       "no bgp tcp-keepalive [(1-65535) (1-65535) (1-30)]",
 | |
|       NO_STR
 | |
|       BGP_STR
 | |
|       "TCP keepalive parameters\n"
 | |
|       "TCP keepalive idle time (seconds)\n"
 | |
|       "TCP keepalive interval (seconds)\n"
 | |
|       "TCP keepalive maximum probes\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp_tcp_keepalive_unset(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_client_to_client_reflection,
 | |
|        bgp_client_to_client_reflection_cmd,
 | |
|        "bgp client-to-client reflection",
 | |
|        BGP_STR
 | |
|        "Configure client to client route reflection\n"
 | |
|        "reflection of routes allowed\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT);
 | |
| 	bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_client_to_client_reflection,
 | |
|        no_bgp_client_to_client_reflection_cmd,
 | |
|        "no bgp client-to-client reflection",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure client to client route reflection\n"
 | |
|        "reflection of routes allowed\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT);
 | |
| 	bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp always-compare-med" configuration. */
 | |
| DEFUN (bgp_always_compare_med,
 | |
|        bgp_always_compare_med_cmd,
 | |
|        "bgp always-compare-med",
 | |
|        BGP_STR
 | |
|        "Allow comparing MED from different neighbors\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_ALWAYS_COMPARE_MED);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_always_compare_med,
 | |
|        no_bgp_always_compare_med_cmd,
 | |
|        "no bgp always-compare-med",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Allow comparing MED from different neighbors\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_ALWAYS_COMPARE_MED);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN(bgp_ebgp_requires_policy, bgp_ebgp_requires_policy_cmd,
 | |
|       "bgp ebgp-requires-policy",
 | |
|       BGP_STR
 | |
|       "Require in and out policy for eBGP peers (RFC8212)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd,
 | |
|       "no bgp ebgp-requires-policy",
 | |
|       NO_STR
 | |
|       BGP_STR
 | |
|       "Require in and out policy for eBGP peers (RFC8212)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_lu_uses_explicit_null, bgp_lu_uses_explicit_null_cmd,
 | |
|       "[no] bgp labeled-unicast <explicit-null|ipv4-explicit-null|ipv6-explicit-null>$value",
 | |
|       NO_STR BGP_STR
 | |
|       "BGP Labeled-unicast options\n"
 | |
|       "Use explicit-null label values for all local prefixes\n"
 | |
|       "Use the IPv4 explicit-null label value for IPv4 local prefixes\n"
 | |
|       "Use the IPv6 explicit-null label value for IPv6 local prefixes\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	uint64_t label_mode;
 | |
| 
 | |
| 	if (strmatch(value, "ipv4-explicit-null"))
 | |
| 		label_mode = BGP_FLAG_LU_IPV4_EXPLICIT_NULL;
 | |
| 	else if (strmatch(value, "ipv6-explicit-null"))
 | |
| 		label_mode = BGP_FLAG_LU_IPV6_EXPLICIT_NULL;
 | |
| 	else
 | |
| 		label_mode = BGP_FLAG_LU_IPV4_EXPLICIT_NULL |
 | |
| 			     BGP_FLAG_LU_IPV6_EXPLICIT_NULL;
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(bgp->flags, label_mode);
 | |
| 	else
 | |
| 		SET_FLAG(bgp->flags, label_mode);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(bgp_suppress_duplicates, bgp_suppress_duplicates_cmd,
 | |
|       "bgp suppress-duplicates",
 | |
|       BGP_STR
 | |
|       "Suppress duplicate updates if the route actually not changed\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_suppress_duplicates, no_bgp_suppress_duplicates_cmd,
 | |
|       "no bgp suppress-duplicates",
 | |
|       NO_STR
 | |
|       BGP_STR
 | |
|       "Suppress duplicate updates if the route actually not changed\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd,
 | |
|       "bgp reject-as-sets",
 | |
|       BGP_STR
 | |
|       "Reject routes with AS_SET or AS_CONFED_SET flag\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	bgp->reject_as_sets = true;
 | |
| 
 | |
| 	/* Reset existing BGP sessions to reject routes
 | |
| 	 * with aspath containing AS_SET or AS_CONFED_SET.
 | |
| 	 */
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 		if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
 | |
| 			peer->last_reset = PEER_DOWN_AS_SETS_REJECT;
 | |
| 			bgp_notify_send(peer, BGP_NOTIFY_CEASE,
 | |
| 					BGP_NOTIFY_CEASE_CONFIG_CHANGE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd,
 | |
|       "no bgp reject-as-sets",
 | |
|       NO_STR
 | |
|       BGP_STR
 | |
|       "Reject routes with AS_SET or AS_CONFED_SET flag\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	bgp->reject_as_sets = false;
 | |
| 
 | |
| 	/* Reset existing BGP sessions to reject routes
 | |
| 	 * with aspath containing AS_SET or AS_CONFED_SET.
 | |
| 	 */
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 		if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
 | |
| 			peer->last_reset = PEER_DOWN_AS_SETS_REJECT;
 | |
| 			bgp_notify_send(peer, BGP_NOTIFY_CEASE,
 | |
| 					BGP_NOTIFY_CEASE_CONFIG_CHANGE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp deterministic-med" configuration. */
 | |
| DEFUN (bgp_deterministic_med,
 | |
|        bgp_deterministic_med_cmd,
 | |
|        "bgp deterministic-med",
 | |
|        BGP_STR
 | |
|        "Pick the best-MED path among paths advertised from the neighboring AS\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (!CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)) {
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED);
 | |
| 		bgp_recalculate_all_bestpaths(bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_deterministic_med,
 | |
|        no_bgp_deterministic_med_cmd,
 | |
|        "no bgp deterministic-med",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Pick the best-MED path among paths advertised from the neighboring AS\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int bestpath_per_as_used;
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	struct peer *peer;
 | |
| 	struct listnode *node, *nnode;
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)) {
 | |
| 		bestpath_per_as_used = 0;
 | |
| 
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			FOREACH_AFI_SAFI (afi, safi)
 | |
| 				if (bgp_addpath_dmed_required(
 | |
| 					peer->addpath_type[afi][safi])) {
 | |
| 					bestpath_per_as_used = 1;
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 			if (bestpath_per_as_used)
 | |
| 				break;
 | |
| 		}
 | |
| 
 | |
| 		if (bestpath_per_as_used) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp deterministic-med cannot be disabled while addpath-tx-bestpath-per-AS is in use\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		} else {
 | |
| 			UNSET_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED);
 | |
| 			bgp_recalculate_all_bestpaths(bgp);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp graceful-restart mode" configuration. */
 | |
| DEFUN (bgp_graceful_restart,
 | |
| 	bgp_graceful_restart_cmd,
 | |
| 	"bgp graceful-restart",
 | |
| 	BGP_STR
 | |
| 	GR_CMD
 | |
|       )
 | |
| {
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START ");
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
 | |
| 							      ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset all peers to take effect\n");
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart,
 | |
| 	no_bgp_graceful_restart_cmd,
 | |
| 	"no bgp graceful-restart",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	NO_GR_CMD
 | |
|       )
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START ");
 | |
| 
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
 | |
| 							      ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset all peers to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_stalepath_time,
 | |
| 	bgp_graceful_restart_stalepath_time_cmd,
 | |
| 	"bgp graceful-restart stalepath-time (1-4095)",
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Set the max time to hold onto restarting peer's stale paths\n"
 | |
| 	"Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t stalepath;
 | |
| 
 | |
| 	stalepath = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	bgp->stalepath_time = stalepath;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_restart_time,
 | |
| 	bgp_graceful_restart_restart_time_cmd,
 | |
| 	"bgp graceful-restart restart-time (0-4095)",
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Set the time to wait to delete stale routes before a BGP open message is received\n"
 | |
| 	"Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t restart;
 | |
| 
 | |
| 	restart = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	bgp->restart_time = restart;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_select_defer_time,
 | |
|        bgp_graceful_restart_select_defer_time_cmd,
 | |
|        "bgp graceful-restart select-defer-time (0-3600)",
 | |
|        BGP_STR
 | |
|        "Graceful restart capability parameters\n"
 | |
|        "Set the time to defer the BGP route selection after restart\n"
 | |
|        "Delay value (seconds, 0 - disable)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t defer_time;
 | |
| 
 | |
| 	defer_time = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	bgp->select_defer_time = defer_time;
 | |
| 	if (defer_time == 0)
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE);
 | |
| 	else
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_stalepath_time,
 | |
| 	no_bgp_graceful_restart_stalepath_time_cmd,
 | |
| 	"no bgp graceful-restart stalepath-time [(1-4095)]",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Set the max time to hold onto restarting peer's stale paths\n"
 | |
| 	"Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_restart_time,
 | |
| 	no_bgp_graceful_restart_restart_time_cmd,
 | |
| 	"no bgp graceful-restart restart-time [(0-4095)]",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Set the time to wait to delete stale routes before a BGP open message is received\n"
 | |
| 	"Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_select_defer_time,
 | |
|        no_bgp_graceful_restart_select_defer_time_cmd,
 | |
|        "no bgp graceful-restart select-defer-time [(0-3600)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Graceful restart capability parameters\n"
 | |
|        "Set the time to defer the BGP route selection after restart\n"
 | |
|        "Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_preserve_fw,
 | |
| 	bgp_graceful_restart_preserve_fw_cmd,
 | |
| 	"bgp graceful-restart preserve-fw-state",
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_preserve_fw,
 | |
| 	no_bgp_graceful_restart_preserve_fw_cmd,
 | |
| 	"no bgp graceful-restart preserve-fw-state",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_graceful_restart_notification,
 | |
| 	bgp_graceful_restart_notification_cmd,
 | |
| 	"[no$no] bgp graceful-restart notification",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	"Graceful restart capability parameters\n"
 | |
| 	"Indicate Graceful Restart support for BGP NOTIFICATION messages\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);
 | |
| 	else
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_administrative_reset,
 | |
| 	bgp_administrative_reset_cmd,
 | |
| 	"[no$no] bgp hard-administrative-reset",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	"Send Hard Reset CEASE Notification for 'Administrative Reset'\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET);
 | |
| 	else
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_disable,
 | |
| 	bgp_graceful_restart_disable_cmd,
 | |
| 	"bgp graceful-restart-disable",
 | |
| 	BGP_STR
 | |
| 	GR_DISABLE)
 | |
| {
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_graceful_restart_disable_cmd : START ");
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
 | |
| 				bgp->peer, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset all peers to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_disable,
 | |
| 	no_bgp_graceful_restart_disable_cmd,
 | |
| 	"no bgp graceful-restart-disable",
 | |
| 	NO_STR
 | |
| 	BGP_STR
 | |
| 	NO_GR_DISABLE
 | |
|       )
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_graceful_restart_disable_cmd : START ");
 | |
| 
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
 | |
| 							      ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_graceful_restart_disable_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset all peers to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_neighbor_graceful_restart_set,
 | |
| 	bgp_neighbor_graceful_restart_set_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	GR_NEIGHBOR_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START ");
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_neighbor_graceful_restart,
 | |
| 	no_bgp_neighbor_graceful_restart_set_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
 | |
| 	NO_STR
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	NO_GR_NEIGHBOR_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START ");
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_neighbor_graceful_restart_helper_set,
 | |
| 	bgp_neighbor_graceful_restart_helper_set_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	GR_NEIGHBOR_HELPER_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START ");
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_neighbor_graceful_restart_helper,
 | |
| 	no_bgp_neighbor_graceful_restart_helper_set_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
 | |
| 	NO_STR
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	NO_GR_NEIGHBOR_HELPER_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START ");
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_neighbor_graceful_restart_disable_set,
 | |
| 	bgp_neighbor_graceful_restart_disable_set_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	GR_NEIGHBOR_DISABLE_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START ");
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD);
 | |
| 
 | |
| 	if (peer->bgp->t_startup)
 | |
| 		bgp_peer_gr_flags_update(peer);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_neighbor_graceful_restart_disable,
 | |
| 	no_bgp_neighbor_graceful_restart_disable_set_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
 | |
| 	NO_STR
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	NO_GR_NEIGHBOR_DISABLE_CMD
 | |
|       )
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int ret = BGP_GR_FAILURE;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START ");
 | |
| 
 | |
| 	ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
 | |
| 
 | |
| 	VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
 | |
| 	VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
 | |
| 
 | |
| 	if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
 | |
| 		zlog_debug(
 | |
| 			"[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END ");
 | |
| 	vty_out(vty,
 | |
| 		"Graceful restart configuration changed, reset this peer to take effect\n");
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFPY (neighbor_graceful_shutdown,
 | |
|        neighbor_graceful_shutdown_cmd,
 | |
|        "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor graceful-shutdown",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Graceful shutdown\n")
 | |
| {
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	struct peer *peer;
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (no)
 | |
| 		ret = peer_flag_unset_vty(vty, neighbor,
 | |
| 					  PEER_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 	else
 | |
| 		ret = peer_flag_set_vty(vty, neighbor,
 | |
| 					PEER_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 
 | |
| 	FOREACH_AFI_SAFI (afi, safi) {
 | |
| 		if (!peer->afc[afi][safi])
 | |
| 			continue;
 | |
| 
 | |
| 		bgp_clear(vty, bgp, afi, safi, clear_peer, BGP_CLEAR_SOFT_IN,
 | |
| 			  neighbor);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
 | |
|               bgp_graceful_restart_disable_eor_cmd,
 | |
|               "bgp graceful-restart disable-eor",
 | |
|               BGP_STR
 | |
|               "Graceful restart configuration parameters\n"
 | |
|               "Disable EOR Check\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_GR_DISABLE_EOR);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_HIDDEN (no_bgp_graceful_restart_disable_eor,
 | |
|               no_bgp_graceful_restart_disable_eor_cmd,
 | |
|               "no bgp graceful-restart disable-eor",
 | |
|               NO_STR
 | |
|               BGP_STR
 | |
|               "Graceful restart configuration parameters\n"
 | |
|               "Disable EOR Check\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_GR_DISABLE_EOR);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_graceful_restart_rib_stale_time,
 | |
|        bgp_graceful_restart_rib_stale_time_cmd,
 | |
|        "bgp graceful-restart rib-stale-time (1-3600)",
 | |
|        BGP_STR
 | |
|        "Graceful restart configuration parameters\n"
 | |
|        "Specify the stale route removal timer in rib\n"
 | |
|        "Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t stale_time;
 | |
| 
 | |
| 	stale_time = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	bgp->rib_stale_time = stale_time;
 | |
| 	/* Send the stale timer update message to RIB */
 | |
| 	if (bgp_zebra_stale_timer_update(bgp))
 | |
| 		return CMD_WARNING;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_restart_rib_stale_time,
 | |
|        no_bgp_graceful_restart_rib_stale_time_cmd,
 | |
|        "no bgp graceful-restart rib-stale-time [(1-3600)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Graceful restart configuration parameters\n"
 | |
|        "Specify the stale route removal timer in rib\n"
 | |
|        "Delay value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
 | |
| 	/* Send the stale timer update message to RIB */
 | |
| 	if (bgp_zebra_stale_timer_update(bgp))
 | |
| 		return CMD_WARNING;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd,
 | |
|       "bgp long-lived-graceful-restart stale-time (1-16777215)",
 | |
|       BGP_STR
 | |
|       "Enable Long-lived Graceful Restart\n"
 | |
|       "Specifies maximum time to wait before purging long-lived stale routes\n"
 | |
|       "Stale time value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	uint32_t llgr_stale_time;
 | |
| 
 | |
| 	llgr_stale_time = strtoul(argv[3]->arg, NULL, 10);
 | |
| 	bgp->llgr_stale_time = llgr_stale_time;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd,
 | |
|       "no bgp long-lived-graceful-restart stale-time [(1-16777215)]",
 | |
|       NO_STR BGP_STR
 | |
|       "Enable Long-lived Graceful Restart\n"
 | |
|       "Specifies maximum time to wait before purging long-lived stale routes\n"
 | |
|       "Stale time value (seconds)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static inline void bgp_initiate_graceful_shut_unshut(struct vty *vty,
 | |
| 						     struct bgp *bgp)
 | |
| {
 | |
| 	bgp_static_redo_import_check(bgp);
 | |
| 	bgp_redistribute_redo(bgp);
 | |
| 	bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 	bgp_clear_star_soft_in(vty, bgp->name);
 | |
| }
 | |
| 
 | |
| static int bgp_global_graceful_shutdown_config_vty(struct vty *vty)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 	bool vrf_cfg = false;
 | |
| 
 | |
| 	if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/* See if graceful-shutdown is set per-vrf and warn user to delete */
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% graceful-shutdown configuration found in vrf %s\n",
 | |
| 				bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ?
 | |
| 					VRF_DEFAULT_NAME : bgp->name);
 | |
| 			vrf_cfg = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (vrf_cfg) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: global graceful-shutdown not permitted\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	/* Set flag globally */
 | |
| 	SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 
 | |
| 	/* Initiate processing for all BGP instances. */
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
 | |
| 		bgp_initiate_graceful_shut_unshut(vty, bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_global_graceful_shutdown_deconfig_vty(struct vty *vty)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/* Unset flag globally */
 | |
| 	UNSET_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 
 | |
| 	/* Initiate processing for all BGP instances. */
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
 | |
| 		bgp_initiate_graceful_shut_unshut(vty, bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp graceful-shutdown" configuration */
 | |
| DEFUN (bgp_graceful_shutdown,
 | |
|        bgp_graceful_shutdown_cmd,
 | |
|        "bgp graceful-shutdown",
 | |
|        BGP_STR
 | |
|        "Graceful shutdown parameters\n")
 | |
| {
 | |
| 	if (vty->node == CONFIG_NODE)
 | |
| 		return bgp_global_graceful_shutdown_config_vty(vty);
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* if configured globally, per-instance config is not allowed */
 | |
| 	if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: per-vrf graceful-shutdown config not permitted with global graceful-shutdown\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 		bgp_initiate_graceful_shut_unshut(vty, bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_graceful_shutdown,
 | |
|        no_bgp_graceful_shutdown_cmd,
 | |
|        "no bgp graceful-shutdown",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Graceful shutdown parameters\n")
 | |
| {
 | |
| 	if (vty->node == CONFIG_NODE)
 | |
| 		return bgp_global_graceful_shutdown_deconfig_vty(vty);
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* If configured globally, cannot remove from one bgp instance */
 | |
| 	if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) {
 | |
| 		vty_out(vty,
 | |
| 			"%%Failed: bgp graceful-shutdown configured globally. Delete per-vrf not permitted\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN);
 | |
| 		bgp_initiate_graceful_shut_unshut(vty, bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp fast-external-failover" configuration. */
 | |
| DEFUN (bgp_fast_external_failover,
 | |
|        bgp_fast_external_failover_cmd,
 | |
|        "bgp fast-external-failover",
 | |
|        BGP_STR
 | |
|        "Immediately reset session if a link to a directly connected external peer goes down\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_fast_external_failover,
 | |
|        no_bgp_fast_external_failover_cmd,
 | |
|        "no bgp fast-external-failover",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Immediately reset session if a link to a directly connected external peer goes down\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_bestpath_aigp,
 | |
|        bgp_bestpath_aigp_cmd,
 | |
|        "[no$no] bgp bestpath aigp",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "Evaluate the AIGP attribute during the best path selection process\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
 | |
| 	else
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
 | |
| 
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath compare-routerid" configuration.  */
 | |
| DEFUN (bgp_bestpath_compare_router_id,
 | |
|        bgp_bestpath_compare_router_id_cmd,
 | |
|        "bgp bestpath compare-routerid",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "Compare router-id for identical EBGP paths\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_bestpath_compare_router_id,
 | |
|        no_bgp_bestpath_compare_router_id_cmd,
 | |
|        "no bgp bestpath compare-routerid",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "Compare router-id for identical EBGP paths\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath as-path ignore" configuration.  */
 | |
| DEFUN (bgp_bestpath_aspath_ignore,
 | |
|        bgp_bestpath_aspath_ignore_cmd,
 | |
|        "bgp bestpath as-path ignore",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Ignore as-path length in selecting a route\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_bestpath_aspath_ignore,
 | |
|        no_bgp_bestpath_aspath_ignore_cmd,
 | |
|        "no bgp bestpath as-path ignore",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Ignore as-path length in selecting a route\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath as-path confed" configuration.  */
 | |
| DEFUN (bgp_bestpath_aspath_confed,
 | |
|        bgp_bestpath_aspath_confed_cmd,
 | |
|        "bgp bestpath as-path confed",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Compare path lengths including confederation sets & sequences in selecting a route\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_bestpath_aspath_confed,
 | |
|        no_bgp_bestpath_aspath_confed_cmd,
 | |
|        "no bgp bestpath as-path confed",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Compare path lengths including confederation sets & sequences in selecting a route\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath as-path multipath-relax" configuration.  */
 | |
| DEFUN (bgp_bestpath_aspath_multipath_relax,
 | |
|        bgp_bestpath_aspath_multipath_relax_cmd,
 | |
|        "bgp bestpath as-path multipath-relax [<as-set|no-as-set>]",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Allow load sharing across routes that have different AS paths (but same length)\n"
 | |
|        "Generate an AS_SET\n"
 | |
|        "Do not generate an AS_SET\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx = 0;
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX);
 | |
| 
 | |
| 	/* no-as-set is now the default behavior so we can silently
 | |
| 	 * ignore it */
 | |
| 	if (argv_find(argv, argc, "as-set", &idx))
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
 | |
| 	else
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
 | |
| 
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_bestpath_aspath_multipath_relax,
 | |
|        no_bgp_bestpath_aspath_multipath_relax_cmd,
 | |
|        "no bgp bestpath as-path multipath-relax [<as-set|no-as-set>]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "AS-path attribute\n"
 | |
|        "Allow load sharing across routes that have different AS paths (but same length)\n"
 | |
|        "Generate an AS_SET\n"
 | |
|        "Do not generate an AS_SET\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath peer-type multipath-relax" configuration. */
 | |
| DEFUN(bgp_bestpath_peer_type_multipath_relax,
 | |
|       bgp_bestpath_peer_type_multipath_relax_cmd,
 | |
|       "bgp bestpath peer-type multipath-relax",
 | |
|       BGP_STR
 | |
|       "Change the default bestpath selection\n"
 | |
|       "Peer type\n"
 | |
|       "Allow load sharing across routes learned from different peer types\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_bestpath_peer_type_multipath_relax,
 | |
|       no_bgp_bestpath_peer_type_multipath_relax_cmd,
 | |
|       "no bgp bestpath peer-type multipath-relax",
 | |
|       NO_STR BGP_STR
 | |
|       "Change the default bestpath selection\n"
 | |
|       "Peer type\n"
 | |
|       "Allow load sharing across routes learned from different peer types\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX);
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp log-neighbor-changes" configuration.  */
 | |
| DEFUN (bgp_log_neighbor_changes,
 | |
|        bgp_log_neighbor_changes_cmd,
 | |
|        "bgp log-neighbor-changes",
 | |
|        BGP_STR
 | |
|        "Log neighbor up/down and reset reason\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_log_neighbor_changes,
 | |
|        no_bgp_log_neighbor_changes_cmd,
 | |
|        "no bgp log-neighbor-changes",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Log neighbor up/down and reset reason\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath med" configuration. */
 | |
| DEFUN (bgp_bestpath_med,
 | |
|        bgp_bestpath_med_cmd,
 | |
|        "bgp bestpath med <confed [missing-as-worst]|missing-as-worst [confed]>",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "MED attribute\n"
 | |
|        "Compare MED among confederation paths\n"
 | |
|        "Treat missing MED as the least preferred one\n"
 | |
|        "Treat missing MED as the least preferred one\n"
 | |
|        "Compare MED among confederation paths\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	int idx = 0;
 | |
| 	if (argv_find(argv, argc, "confed", &idx))
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_MED_CONFED);
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "missing-as-worst", &idx))
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST);
 | |
| 
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_bestpath_med,
 | |
|        no_bgp_bestpath_med_cmd,
 | |
|        "no bgp bestpath med <confed [missing-as-worst]|missing-as-worst [confed]>",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "MED attribute\n"
 | |
|        "Compare MED among confederation paths\n"
 | |
|        "Treat missing MED as the least preferred one\n"
 | |
|        "Treat missing MED as the least preferred one\n"
 | |
|        "Compare MED among confederation paths\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	int idx = 0;
 | |
| 	if (argv_find(argv, argc, "confed", &idx))
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_MED_CONFED);
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "missing-as-worst", &idx))
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST);
 | |
| 
 | |
| 	bgp_recalculate_all_bestpaths(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp bestpath bandwidth" configuration. */
 | |
| DEFPY (bgp_bestpath_bw,
 | |
|        bgp_bestpath_bw_cmd,
 | |
|        "bgp bestpath bandwidth <ignore|skip-missing|default-weight-for-missing>$bw_cfg",
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "Link Bandwidth attribute\n"
 | |
|        "Ignore link bandwidth (i.e., do regular ECMP, not weighted)\n"
 | |
|        "Ignore paths without link bandwidth for ECMP (if other paths have it)\n"
 | |
|        "Assign a low default weight (value 1) to paths not having link bandwidth\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	if (!bw_cfg) {
 | |
| 		vty_out(vty, "%% Bandwidth configuration must be specified\n");
 | |
| 		return CMD_ERR_INCOMPLETE;
 | |
| 	}
 | |
| 	if (!strcmp(bw_cfg, "ignore"))
 | |
| 		bgp->lb_handling = BGP_LINK_BW_IGNORE_BW;
 | |
| 	else if (!strcmp(bw_cfg, "skip-missing"))
 | |
| 		bgp->lb_handling = BGP_LINK_BW_SKIP_MISSING;
 | |
| 	else if (!strcmp(bw_cfg, "default-weight-for-missing"))
 | |
| 		bgp->lb_handling = BGP_LINK_BW_DEFWT_4_MISSING;
 | |
| 	else
 | |
| 		return CMD_ERR_NO_MATCH;
 | |
| 
 | |
| 	/* This config is used in route install, so redo that. */
 | |
| 	FOREACH_AFI_SAFI (afi, safi) {
 | |
| 		if (!bgp_fibupd_safi(safi))
 | |
| 			continue;
 | |
| 		bgp_zebra_announce_table(bgp, afi, safi);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_bestpath_bw,
 | |
|        no_bgp_bestpath_bw_cmd,
 | |
|        "no bgp bestpath bandwidth [<ignore|skip-missing|default-weight-for-missing>$bw_cfg]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Change the default bestpath selection\n"
 | |
|        "Link Bandwidth attribute\n"
 | |
|        "Ignore link bandwidth (i.e., do regular ECMP, not weighted)\n"
 | |
|        "Ignore paths without link bandwidth for ECMP (if other paths have it)\n"
 | |
|        "Assign a low default weight (value 1) to paths not having link bandwidth\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	bgp->lb_handling = BGP_LINK_BW_ECMP;
 | |
| 
 | |
| 	/* This config is used in route install, so redo that. */
 | |
| 	FOREACH_AFI_SAFI (afi, safi) {
 | |
| 		if (!bgp_fibupd_safi(safi))
 | |
| 			continue;
 | |
| 		bgp_zebra_announce_table(bgp, afi, safi);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd,
 | |
|       "[no] bgp default <ipv4-unicast|"
 | |
|       "ipv4-multicast|"
 | |
|       "ipv4-vpn|"
 | |
|       "ipv4-labeled-unicast|"
 | |
|       "ipv4-flowspec|"
 | |
|       "ipv6-unicast|"
 | |
|       "ipv6-multicast|"
 | |
|       "ipv6-vpn|"
 | |
|       "ipv6-labeled-unicast|"
 | |
|       "ipv6-flowspec|"
 | |
|       "l2vpn-evpn>$afi_safi",
 | |
|       NO_STR
 | |
|       BGP_STR
 | |
|       "Configure BGP defaults\n"
 | |
|       "Activate ipv4-unicast for a peer by default\n"
 | |
|       "Activate ipv4-multicast for a peer by default\n"
 | |
|       "Activate ipv4-vpn for a peer by default\n"
 | |
|       "Activate ipv4-labeled-unicast for a peer by default\n"
 | |
|       "Activate ipv4-flowspec for a peer by default\n"
 | |
|       "Activate ipv6-unicast for a peer by default\n"
 | |
|       "Activate ipv6-multicast for a peer by default\n"
 | |
|       "Activate ipv6-vpn for a peer by default\n"
 | |
|       "Activate ipv6-labeled-unicast for a peer by default\n"
 | |
|       "Activate ipv6-flowspec for a peer by default\n"
 | |
|       "Activate l2vpn-evpn for a peer by default\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	char afi_safi_str[strlen(afi_safi) + 1];
 | |
| 	char *afi_safi_str_tok;
 | |
| 
 | |
| 	strlcpy(afi_safi_str, afi_safi, sizeof(afi_safi_str));
 | |
| 	char *afi_str = strtok_r(afi_safi_str, "-", &afi_safi_str_tok);
 | |
| 	char *safi_str = strtok_r(NULL, "-", &afi_safi_str_tok);
 | |
| 	afi_t afi = bgp_vty_afi_from_str(afi_str);
 | |
| 	safi_t safi;
 | |
| 
 | |
| 	/*
 | |
| 	 * Impossible situation but making coverity happy
 | |
| 	 */
 | |
| 	assert(afi != AFI_MAX);
 | |
| 
 | |
| 	if (strmatch(safi_str, "labeled"))
 | |
| 		safi = bgp_vty_safi_from_str("labeled-unicast");
 | |
| 	else
 | |
| 		safi = bgp_vty_safi_from_str(safi_str);
 | |
| 
 | |
| 	assert(safi != SAFI_MAX);
 | |
| 	if (no)
 | |
| 		bgp->default_af[afi][safi] = false;
 | |
| 	else {
 | |
| 		if ((safi == SAFI_LABELED_UNICAST
 | |
| 		     && bgp->default_af[afi][SAFI_UNICAST])
 | |
| 		    || (safi == SAFI_UNICAST
 | |
| 			&& bgp->default_af[afi][SAFI_LABELED_UNICAST]))
 | |
| 			bgp_vty_return(vty, BGP_ERR_PEER_SAFI_CONFLICT);
 | |
| 		else
 | |
| 			bgp->default_af[afi][safi] = true;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Display hostname in certain command outputs */
 | |
| DEFUN (bgp_default_show_hostname,
 | |
|        bgp_default_show_hostname_cmd,
 | |
|        "bgp default show-hostname",
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "Show hostname in certain command outputs\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_SHOW_HOSTNAME);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_default_show_hostname,
 | |
|        no_bgp_default_show_hostname_cmd,
 | |
|        "no bgp default show-hostname",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "Show hostname in certain command outputs\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_SHOW_HOSTNAME);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Display hostname in certain command outputs */
 | |
| DEFUN (bgp_default_show_nexthop_hostname,
 | |
|        bgp_default_show_nexthop_hostname_cmd,
 | |
|        "bgp default show-nexthop-hostname",
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "Show hostname for nexthop in certain command outputs\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_default_show_nexthop_hostname,
 | |
|        no_bgp_default_show_nexthop_hostname_cmd,
 | |
|        "no bgp default show-nexthop-hostname",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "Show hostname for nexthop in certain command outputs\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "bgp network import-check" configuration.  */
 | |
| DEFUN (bgp_network_import_check,
 | |
|        bgp_network_import_check_cmd,
 | |
|        "bgp network import-check",
 | |
|        BGP_STR
 | |
|        "BGP network command\n"
 | |
|        "Check BGP network route exists in IGP\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	if (!CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)) {
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK);
 | |
| 		bgp_static_redo_import_check(bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_network_import_check, bgp_network_import_check_exact_cmd,
 | |
| 	     "bgp network import-check exact",
 | |
| 	     BGP_STR
 | |
| 	     "BGP network command\n"
 | |
| 	     "Check BGP network route exists in IGP\n"
 | |
| 	     "Match route precisely\n")
 | |
| 
 | |
| DEFUN (no_bgp_network_import_check,
 | |
|        no_bgp_network_import_check_cmd,
 | |
|        "no bgp network import-check",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "BGP network command\n"
 | |
|        "Check BGP network route exists in IGP\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)) {
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK);
 | |
| 		bgp_static_redo_import_check(bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_default_local_preference,
 | |
|        bgp_default_local_preference_cmd,
 | |
|        "bgp default local-preference (0-4294967295)",
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "local preference (higher=more preferred)\n"
 | |
|        "Configure default local preference value\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t local_pref;
 | |
| 
 | |
| 	local_pref = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp_default_local_preference_set(bgp, local_pref);
 | |
| 	bgp_clear_star_soft_in(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_default_local_preference,
 | |
|        no_bgp_default_local_preference_cmd,
 | |
|        "no bgp default local-preference [(0-4294967295)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "local preference (higher=more preferred)\n"
 | |
|        "Configure default local preference value\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_default_local_preference_unset(bgp);
 | |
| 	bgp_clear_star_soft_in(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (bgp_default_subgroup_pkt_queue_max,
 | |
|        bgp_default_subgroup_pkt_queue_max_cmd,
 | |
|        "bgp default subgroup-pkt-queue-max (20-100)",
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "subgroup-pkt-queue-max\n"
 | |
|        "Configure subgroup packet queue max\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t max_size;
 | |
| 
 | |
| 	max_size = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp_default_subgroup_pkt_queue_max_set(bgp, max_size);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_default_subgroup_pkt_queue_max,
 | |
|        no_bgp_default_subgroup_pkt_queue_max_cmd,
 | |
|        "no bgp default subgroup-pkt-queue-max [(20-100)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "subgroup-pkt-queue-max\n"
 | |
|        "Configure subgroup packet queue max\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_default_subgroup_pkt_queue_max_unset(bgp);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (bgp_rr_allow_outbound_policy,
 | |
|        bgp_rr_allow_outbound_policy_cmd,
 | |
|        "bgp route-reflector allow-outbound-policy",
 | |
|        BGP_STR
 | |
|        "Allow modifications made by out route-map\n"
 | |
|        "on ibgp neighbors\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (!CHECK_FLAG(bgp->flags, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
 | |
| 		SET_FLAG(bgp->flags, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
 | |
| 		update_group_announce_rrclients(bgp);
 | |
| 		bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_rr_allow_outbound_policy,
 | |
|        no_bgp_rr_allow_outbound_policy_cmd,
 | |
|        "no bgp route-reflector allow-outbound-policy",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Allow modifications made by out route-map\n"
 | |
|        "on ibgp neighbors\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
 | |
| 		UNSET_FLAG(bgp->flags, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
 | |
| 		update_group_announce_rrclients(bgp);
 | |
| 		bgp_clear_star_soft_out(vty, bgp->name);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_listen_limit,
 | |
|        bgp_listen_limit_cmd,
 | |
|        "bgp listen limit (1-65535)",
 | |
|        BGP_STR
 | |
|        "BGP Dynamic Neighbors listen commands\n"
 | |
|        "Maximum number of BGP Dynamic Neighbors that can be created\n"
 | |
|        "Configure Dynamic Neighbors listen limit value\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_number = 3;
 | |
| 	int listen_limit;
 | |
| 
 | |
| 	listen_limit = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	bgp_listen_limit_set(bgp, listen_limit);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_listen_limit,
 | |
|        no_bgp_listen_limit_cmd,
 | |
|        "no bgp listen limit [(1-65535)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "BGP Dynamic Neighbors listen commands\n"
 | |
|        "Maximum number of BGP Dynamic Neighbors that can be created\n"
 | |
|        "Configure Dynamic Neighbors listen limit value\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp_listen_limit_unset(bgp);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Check if this listen range is already configured. Check for exact
 | |
|  * match or overlap based on input.
 | |
|  */
 | |
| static struct peer_group *listen_range_exists(struct bgp *bgp,
 | |
| 					      struct prefix *range, int exact)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct listnode *node1, *nnode1;
 | |
| 	struct peer_group *group;
 | |
| 	struct prefix *lr;
 | |
| 	afi_t afi;
 | |
| 	int match;
 | |
| 
 | |
| 	afi = family2afi(range->family);
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
 | |
| 		for (ALL_LIST_ELEMENTS(group->listen_range[afi], node1, nnode1,
 | |
| 				       lr)) {
 | |
| 			if (exact)
 | |
| 				match = prefix_same(range, lr);
 | |
| 			else
 | |
| 				match = (prefix_match(range, lr)
 | |
| 					 || prefix_match(lr, range));
 | |
| 			if (match)
 | |
| 				return group;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_listen_range,
 | |
|        bgp_listen_range_cmd,
 | |
|        "bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME",
 | |
|        BGP_STR
 | |
|        "Configure BGP dynamic neighbors listen range\n"
 | |
|        "Configure BGP dynamic neighbors listen range\n"
 | |
|        NEIGHBOR_ADDR_STR
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct prefix range;
 | |
| 	struct peer_group *group, *existing_group;
 | |
| 	afi_t afi;
 | |
| 	int ret;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	argv_find(argv, argc, "A.B.C.D/M", &idx);
 | |
| 	argv_find(argv, argc, "X:X::X:X/M", &idx);
 | |
| 	char *prefix = argv[idx]->arg;
 | |
| 	argv_find(argv, argc, "PGNAME", &idx);
 | |
| 	char *peergroup = argv[idx]->arg;
 | |
| 
 | |
| 	/* Convert IP prefix string to struct prefix. */
 | |
| 	ret = str2prefix(prefix, &range);
 | |
| 	if (!ret) {
 | |
| 		vty_out(vty, "%% Malformed listen range\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	afi = family2afi(range.family);
 | |
| 
 | |
| 	if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&range.u.prefix6)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Malformed listen range (link-local address)\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	apply_mask(&range);
 | |
| 
 | |
| 	/* Check if same listen range is already configured. */
 | |
| 	existing_group = listen_range_exists(bgp, &range, 1);
 | |
| 	if (existing_group) {
 | |
| 		if (strcmp(existing_group->name, peergroup) == 0)
 | |
| 			return CMD_SUCCESS;
 | |
| 		else {
 | |
| 			vty_out(vty,
 | |
| 				"%% Same listen range is attached to peer-group %s\n",
 | |
| 				existing_group->name);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Check if an overlapping listen range exists. */
 | |
| 	if (listen_range_exists(bgp, &range, 0)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Listen range overlaps with existing listen range\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, peergroup);
 | |
| 	if (!group) {
 | |
| 		vty_out(vty, "%% Configure the peer-group first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_group_listen_range_add(group, &range);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_listen_range,
 | |
|        no_bgp_listen_range_cmd,
 | |
|        "no bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Unconfigure BGP dynamic neighbors listen range\n"
 | |
|        "Unconfigure BGP dynamic neighbors listen range\n"
 | |
|        NEIGHBOR_ADDR_STR
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct prefix range;
 | |
| 	struct peer_group *group;
 | |
| 	afi_t afi;
 | |
| 	int ret;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	argv_find(argv, argc, "A.B.C.D/M", &idx);
 | |
| 	argv_find(argv, argc, "X:X::X:X/M", &idx);
 | |
| 	char *prefix = argv[idx]->arg;
 | |
| 	argv_find(argv, argc, "PGNAME", &idx);
 | |
| 	char *peergroup = argv[idx]->arg;
 | |
| 
 | |
| 	/* Convert IP prefix string to struct prefix. */
 | |
| 	ret = str2prefix(prefix, &range);
 | |
| 	if (!ret) {
 | |
| 		vty_out(vty, "%% Malformed listen range\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	afi = family2afi(range.family);
 | |
| 
 | |
| 	if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&range.u.prefix6)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Malformed listen range (link-local address)\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	apply_mask(&range);
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, peergroup);
 | |
| 	if (!group) {
 | |
| 		vty_out(vty, "%% Peer-group does not exist\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_group_listen_range_del(group, &range);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| void bgp_config_write_listen(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	struct peer_group *group;
 | |
| 	struct listnode *node, *nnode, *rnode, *nrnode;
 | |
| 	struct prefix *range;
 | |
| 	afi_t afi;
 | |
| 
 | |
| 	if (bgp->dynamic_neighbors_limit != BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT)
 | |
| 		vty_out(vty, " bgp listen limit %d\n",
 | |
| 			bgp->dynamic_neighbors_limit);
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
 | |
| 		for (afi = AFI_IP; afi < AFI_MAX; afi++) {
 | |
| 			for (ALL_LIST_ELEMENTS(group->listen_range[afi], rnode,
 | |
| 					       nrnode, range)) {
 | |
| 				vty_out(vty,
 | |
| 					" bgp listen range %pFX peer-group %s\n",
 | |
| 					range, group->name);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (bgp_disable_connected_route_check,
 | |
|        bgp_disable_connected_route_check_cmd,
 | |
|        "bgp disable-ebgp-connected-route-check",
 | |
|        BGP_STR
 | |
|        "Disable checking if nexthop is connected on ebgp sessions\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	SET_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK);
 | |
| 	bgp_clear_star_soft_in(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_disable_connected_route_check,
 | |
|        no_bgp_disable_connected_route_check_cmd,
 | |
|        "no bgp disable-ebgp-connected-route-check",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Disable checking if nexthop is connected on ebgp sessions\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	UNSET_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK);
 | |
| 	bgp_clear_star_soft_in(vty, bgp->name);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
 | |
| 			      const char *as_str)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 	int as_type = AS_SPECIFIED;
 | |
| 	union sockunion su;
 | |
| 
 | |
| 	if (as_str[0] == 'i') {
 | |
| 		as = 0;
 | |
| 		as_type = AS_INTERNAL;
 | |
| 	} else if (as_str[0] == 'e') {
 | |
| 		as = 0;
 | |
| 		as_type = AS_EXTERNAL;
 | |
| 	} else if (!asn_str2asn(as_str, &as))
 | |
| 		as_type = AS_UNSPECIFIED;
 | |
| 
 | |
| 	if (as_type == AS_UNSPECIFIED) {
 | |
| 		vty_out(vty, "%% Invalid peer AS: %s\n", as_str);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	/* If peer is peer group or interface peer, call proper function. */
 | |
| 	ret = str2sockunion(peer_str, &su);
 | |
| 	if (ret < 0) {
 | |
| 		struct peer *peer;
 | |
| 
 | |
| 		/* Check if existing interface peer */
 | |
| 		peer = peer_lookup_by_conf_if(bgp, peer_str);
 | |
| 
 | |
| 		ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, as_str);
 | |
| 
 | |
| 		/* if not interface peer, check peer-group settings */
 | |
| 		if (ret < 0 && !peer) {
 | |
| 			ret = peer_group_remote_as(bgp, peer_str, &as, as_type,
 | |
| 						   as_str);
 | |
| 			if (ret < 0) {
 | |
| 				vty_out(vty,
 | |
| 					"%% Create the peer-group or interface first\n");
 | |
| 				return CMD_WARNING_CONFIG_FAILED;
 | |
| 			}
 | |
| 			return CMD_SUCCESS;
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (peer_address_self_check(bgp, &su)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Can not configure the local system as neighbor\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		ret = peer_remote_as(bgp, &su, NULL, &as, as_type, as_str);
 | |
| 	}
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_default_shutdown,
 | |
|        bgp_default_shutdown_cmd,
 | |
|        "[no] bgp default shutdown",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Configure BGP defaults\n"
 | |
|        "Apply administrative shutdown to newly configured peers\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp->autoshutdown = !strmatch(argv[0]->text, "no");
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_shutdown_msg, bgp_shutdown_msg_cmd, "bgp shutdown message MSG...",
 | |
|       BGP_STR
 | |
|       "Administrative shutdown of the BGP instance\n"
 | |
|       "Add a shutdown message (RFC 8203)\n"
 | |
|       "Shutdown message\n")
 | |
| {
 | |
| 	char *msgstr = NULL;
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (argc > 3)
 | |
| 		msgstr = argv_concat(argv, argc, 3);
 | |
| 
 | |
| 	if (msgstr && strlen(msgstr) > BGP_ADMIN_SHUTDOWN_MSG_LEN) {
 | |
| 		vty_out(vty, "%% Shutdown message size exceeded %d\n",
 | |
| 			BGP_ADMIN_SHUTDOWN_MSG_LEN);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_shutdown_enable(bgp, msgstr);
 | |
| 	XFREE(MTYPE_TMP, msgstr);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_shutdown, bgp_shutdown_cmd, "bgp shutdown",
 | |
|       BGP_STR "Administrative shutdown of the BGP instance\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp_shutdown_enable(bgp, NULL);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(no_bgp_shutdown, no_bgp_shutdown_cmd, "no bgp shutdown",
 | |
|       NO_STR BGP_STR "Administrative shutdown of the BGP instance\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp_shutdown_disable(bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
 | |
|       "no bgp shutdown message MSG...", NO_STR BGP_STR
 | |
|       "Administrative shutdown of the BGP instance\n"
 | |
|       "Add a shutdown message (RFC 8203)\n" "Shutdown message\n")
 | |
| 
 | |
| DEFUN (neighbor_remote_as,
 | |
|        neighbor_remote_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_remote_as = 3;
 | |
| 	return peer_remote_as_vty(vty, argv[idx_peer]->arg,
 | |
| 				  argv[idx_remote_as]->arg);
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_allow_martian,
 | |
|        bgp_allow_martian_cmd,
 | |
|        "[no]$no bgp allow-martian-nexthop",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Allow Martian nexthops to be received in the NLRI from a peer\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (no)
 | |
| 		bgp->allow_martian = false;
 | |
| 	else
 | |
| 		bgp->allow_martian = true;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Enable fast convergence of bgp sessions. If this is enabled, bgp
 | |
|  * sessions do not wait for hold timer expiry to bring down the sessions
 | |
|  * when nexthop becomes unreachable
 | |
|  */
 | |
| DEFUN(bgp_fast_convergence, bgp_fast_convergence_cmd, "bgp fast-convergence",
 | |
|       BGP_STR "Fast convergence for bgp sessions\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp->fast_convergence = true;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(no_bgp_fast_convergence, no_bgp_fast_convergence_cmd,
 | |
|       "no bgp fast-convergence",
 | |
|       NO_STR BGP_STR "Fast convergence for bgp sessions\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp->fast_convergence = false;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
 | |
| 				   int v6only,
 | |
| 				   const char *peer_group_name,
 | |
| 				   const char *as_str)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	as_t as = 0;
 | |
| 	int as_type = AS_UNSPECIFIED;
 | |
| 	struct peer *peer;
 | |
| 	struct peer_group *group;
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, conf_if);
 | |
| 
 | |
| 	if (group) {
 | |
| 		vty_out(vty, "%% Name conflict with peer-group \n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (as_str) {
 | |
| 		if (as_str[0] == 'i') {
 | |
| 			as_type = AS_INTERNAL;
 | |
| 		} else if (as_str[0] == 'e') {
 | |
| 			as_type = AS_EXTERNAL;
 | |
| 		} else {
 | |
| 			/* Get AS number.  */
 | |
| 			if (asn_str2asn(as_str, &as))
 | |
| 				as_type = AS_SPECIFIED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	peer = peer_lookup_by_conf_if(bgp, conf_if);
 | |
| 	if (peer) {
 | |
| 		if (as_str)
 | |
| 			ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type,
 | |
| 					     as_str);
 | |
| 	} else {
 | |
| 		peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
 | |
| 				   NULL, true, as_str);
 | |
| 
 | |
| 		if (!peer) {
 | |
| 			vty_out(vty, "%% BGP failed to create peer\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (v6only)
 | |
| 			peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
 | |
| 
 | |
| 		/* Request zebra to initiate IPv6 RAs on this interface. We do
 | |
| 		 * this
 | |
| 		 * any unnumbered peer in order to not worry about run-time
 | |
| 		 * transitions
 | |
| 		 * (e.g., peering is initially IPv4, but the IPv4 /30 or /31
 | |
| 		 * address
 | |
| 		 * gets deleted later etc.)
 | |
| 		 */
 | |
| 		if (peer->ifp)
 | |
| 			bgp_zebra_initiate_radv(bgp, peer);
 | |
| 	}
 | |
| 
 | |
| 	if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
 | |
| 	    || (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) {
 | |
| 		if (v6only)
 | |
| 			peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
 | |
| 		else
 | |
| 			peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY);
 | |
| 
 | |
| 		/* v6only flag changed. Reset bgp seesion */
 | |
| 		if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
 | |
| 			peer->last_reset = PEER_DOWN_V6ONLY_CHANGE;
 | |
| 			bgp_notify_send(peer, BGP_NOTIFY_CEASE,
 | |
| 					BGP_NOTIFY_CEASE_CONFIG_CHANGE);
 | |
| 		} else
 | |
| 			bgp_session_reset(peer);
 | |
| 	}
 | |
| 
 | |
| 	if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) {
 | |
| 		SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
 | |
| 		SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE);
 | |
| 		SET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
 | |
| 	}
 | |
| 
 | |
| 	if (peer_group_name) {
 | |
| 		group = peer_group_lookup(bgp, peer_group_name);
 | |
| 		if (!group) {
 | |
| 			vty_out(vty, "%% Configure the peer-group first\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		ret = peer_group_bind(bgp, NULL, peer, group, &as);
 | |
| 	}
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_interface_config,
 | |
|        neighbor_interface_config_cmd,
 | |
|        "neighbor WORD interface [peer-group PGNAME]",
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Enable BGP on interface\n"
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	int idx_word = 1;
 | |
| 	int idx_peer_group_word = 4;
 | |
| 
 | |
| 	if (argc > idx_peer_group_word)
 | |
| 		return peer_conf_interface_get(
 | |
| 			vty, argv[idx_word]->arg, 0,
 | |
| 			argv[idx_peer_group_word]->arg, NULL);
 | |
| 	else
 | |
| 		return peer_conf_interface_get(vty, argv[idx_word]->arg, 0,
 | |
| 					       NULL, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_interface_config_v6only,
 | |
|        neighbor_interface_config_v6only_cmd,
 | |
|        "neighbor WORD interface v6only [peer-group PGNAME]",
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Enable BGP on interface\n"
 | |
|        "Enable BGP with v6 link-local only\n"
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	int idx_word = 1;
 | |
| 	int idx_peer_group_word = 5;
 | |
| 
 | |
| 	if (argc > idx_peer_group_word)
 | |
| 		return peer_conf_interface_get(
 | |
| 			vty, argv[idx_word]->arg, 1,
 | |
| 			argv[idx_peer_group_word]->arg, NULL);
 | |
| 
 | |
| 	return peer_conf_interface_get(vty, argv[idx_word]->arg, 1, NULL, NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (neighbor_interface_config_remote_as,
 | |
|        neighbor_interface_config_remote_as_cmd,
 | |
|        "neighbor WORD interface remote-as <ASNUM|internal|external>",
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Enable BGP on interface\n"
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	int idx_word = 1;
 | |
| 	int idx_remote_as = 4;
 | |
| 	return peer_conf_interface_get(vty, argv[idx_word]->arg, 0, NULL,
 | |
| 				       argv[idx_remote_as]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_interface_v6only_config_remote_as,
 | |
|        neighbor_interface_v6only_config_remote_as_cmd,
 | |
|        "neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Enable BGP with v6 link-local only\n"
 | |
|        "Enable BGP on interface\n"
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	int idx_word = 1;
 | |
| 	int idx_remote_as = 5;
 | |
| 	return peer_conf_interface_get(vty, argv[idx_word]->arg, 1, NULL,
 | |
| 				       argv[idx_remote_as]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_peer_group,
 | |
|        neighbor_peer_group_cmd,
 | |
|        "neighbor WORD peer-group",
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Configure peer-group\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_word = 1;
 | |
| 	struct peer *peer;
 | |
| 	struct peer_group *group;
 | |
| 
 | |
| 	peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
 | |
| 	if (peer) {
 | |
| 		vty_out(vty, "%% Name conflict with interface: \n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	group = peer_group_get(bgp, argv[idx_word]->arg);
 | |
| 	if (!group) {
 | |
| 		vty_out(vty, "%% BGP failed to find or create peer-group\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor,
 | |
|        no_neighbor_cmd,
 | |
|        "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external>]>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_peer = 2;
 | |
| 	int ret;
 | |
| 	union sockunion su;
 | |
| 	struct peer_group *group;
 | |
| 	struct peer *peer;
 | |
| 	struct peer *other;
 | |
| 
 | |
| 	ret = str2sockunion(argv[idx_peer]->arg, &su);
 | |
| 	if (ret < 0) {
 | |
| 		/* look up for neighbor by interface name config. */
 | |
| 		peer = peer_lookup_by_conf_if(bgp, argv[idx_peer]->arg);
 | |
| 		if (peer) {
 | |
| 			/* Request zebra to terminate IPv6 RAs on this
 | |
| 			 * interface. */
 | |
| 			if (peer->ifp)
 | |
| 				bgp_zebra_terminate_radv(peer->bgp, peer);
 | |
| 			peer_notify_unconfig(peer);
 | |
| 			peer_delete(peer);
 | |
| 			return CMD_SUCCESS;
 | |
| 		}
 | |
| 
 | |
| 		group = peer_group_lookup(bgp, argv[idx_peer]->arg);
 | |
| 		if (group) {
 | |
| 			peer_group_notify_unconfig(group);
 | |
| 			peer_group_delete(group);
 | |
| 		} else {
 | |
| 			vty_out(vty, "%% Create the peer-group first\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	} else {
 | |
| 		peer = peer_lookup(bgp, &su);
 | |
| 		if (peer) {
 | |
| 			if (peer_dynamic_neighbor(peer)) {
 | |
| 				vty_out(vty,
 | |
| 					"%% Operation not allowed on a dynamic neighbor\n");
 | |
| 				return CMD_WARNING_CONFIG_FAILED;
 | |
| 			}
 | |
| 
 | |
| 			other = peer->doppelganger;
 | |
| 
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
 | |
| 				bgp_zebra_terminate_radv(peer->bgp, peer);
 | |
| 
 | |
| 			peer_notify_unconfig(peer);
 | |
| 			peer_delete(peer);
 | |
| 			if (other && other->status != Deleted) {
 | |
| 				peer_notify_unconfig(other);
 | |
| 				peer_delete(other);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_interface_config,
 | |
|        no_neighbor_interface_config_cmd,
 | |
|        "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name\n"
 | |
|        "Configure BGP on interface\n"
 | |
|        "Enable BGP with v6 link-local only\n"
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n"
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_word = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	/* look up for neighbor by interface name config. */
 | |
| 	peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
 | |
| 	if (peer) {
 | |
| 		/* Request zebra to terminate IPv6 RAs on this interface. */
 | |
| 		if (peer->ifp)
 | |
| 			bgp_zebra_terminate_radv(peer->bgp, peer);
 | |
| 		peer_notify_unconfig(peer);
 | |
| 		peer_delete(peer);
 | |
| 	} else {
 | |
| 		vty_out(vty, "%% Create the bgp interface first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_peer_group,
 | |
|        no_neighbor_peer_group_cmd,
 | |
|        "no neighbor WORD peer-group",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        "Neighbor tag\n"
 | |
|        "Configure peer-group\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_word = 2;
 | |
| 	struct peer_group *group;
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, argv[idx_word]->arg);
 | |
| 	if (group) {
 | |
| 		peer_group_notify_unconfig(group);
 | |
| 		peer_group_delete(group);
 | |
| 	} else {
 | |
| 		vty_out(vty, "%% Create the peer-group first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_interface_peer_group_remote_as,
 | |
|        no_neighbor_interface_peer_group_remote_as_cmd,
 | |
|        "no neighbor WORD remote-as <ASNUM|internal|external>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        "Interface name or neighbor tag\n"
 | |
|        "Specify a BGP neighbor\n"
 | |
|        AS_STR
 | |
|        "Internal BGP peer\n"
 | |
|        "External BGP peer\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_word = 2;
 | |
| 	struct peer_group *group;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	/* look up for neighbor by interface name config. */
 | |
| 	peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
 | |
| 	if (peer) {
 | |
| 		peer_as_change(peer, 0, AS_UNSPECIFIED, NULL);
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, argv[idx_word]->arg);
 | |
| 	if (group)
 | |
| 		peer_group_remote_as_delete(group);
 | |
| 	else {
 | |
| 		vty_out(vty, "%% Create the peer-group or interface first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_local_as,
 | |
|        neighbor_local_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a local-as number\n"
 | |
|        "AS number expressed in dotted or plain format used as local AS\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!asn_str2asn(argv[idx_number]->arg, &as)) {
 | |
| 		vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
 | |
| 			argv[idx_number]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_local_as_set(peer, as, 0, 0, argv[idx_number]->arg);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_local_as_no_prepend,
 | |
|        neighbor_local_as_no_prepend_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a local-as number\n"
 | |
|        "AS number expressed in dotted or plain format used as local AS\n"
 | |
|        "Do not prepend local-as to updates from ebgp peers\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!asn_str2asn(argv[idx_number]->arg, &as)) {
 | |
| 		vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
 | |
| 			argv[idx_number]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_local_as_set(peer, as, 1, 0, argv[idx_number]->arg);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_local_as_no_prepend_replace_as,
 | |
|        neighbor_local_as_no_prepend_replace_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a local-as number\n"
 | |
|        "AS number expressed in dotted or plain format used as local AS\n"
 | |
|        "Do not prepend local-as to updates from ebgp peers\n"
 | |
|        "Do not prepend local-as to updates from ibgp peers\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!asn_str2asn(argv[idx_number]->arg, &as)) {
 | |
| 		vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
 | |
| 			argv[idx_number]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_local_as_set(peer, as, 1, 1, argv[idx_number]->arg);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_local_as,
 | |
|        no_neighbor_local_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Specify a local-as number\n"
 | |
|        "AS number expressed in dotted or plain format used as local AS\n"
 | |
|        "Do not prepend local-as to updates from ebgp peers\n"
 | |
|        "Do not prepend local-as to updates from ibgp peers\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_local_as_unset(peer);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (neighbor_solo,
 | |
|        neighbor_solo_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> solo",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Solo peer - part of its own update group\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = update_group_adjust_soloness(peer, 1);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_solo,
 | |
|        no_neighbor_solo_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> solo",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Solo peer - part of its own update group\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = update_group_adjust_soloness(peer, 0);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_password,
 | |
|        neighbor_password_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> password LINE",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set a password\n"
 | |
|        "The password\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_line = 3;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_password_set(peer, argv[idx_line]->arg);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_password,
 | |
|        no_neighbor_password_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> password [LINE]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set a password\n"
 | |
|        "The password\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_password_unset(peer);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_activate,
 | |
|        neighbor_activate_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> activate",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enable the Address Family for this Neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_activate(peer, bgp_node_afi(vty), bgp_node_safi(vty));
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_activate, neighbor_activate_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> activate",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Enable the Address Family for this Neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_activate,
 | |
|        no_neighbor_activate_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> activate",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enable the Address Family for this Neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	/* Lookup peer. */
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_deactivate(peer, bgp_node_afi(vty), bgp_node_safi(vty));
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_activate, no_neighbor_activate_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> activate",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Enable the Address Family for this Neighbor\n")
 | |
| 
 | |
| DEFUN (neighbor_set_peer_group,
 | |
|        neighbor_set_peer_group_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int ret;
 | |
| 	as_t as;
 | |
| 	union sockunion su;
 | |
| 	struct peer *peer;
 | |
| 	struct peer_group *group;
 | |
| 
 | |
| 	ret = str2sockunion(argv[idx_peer]->arg, &su);
 | |
| 	if (ret < 0) {
 | |
| 		peer = peer_lookup_by_conf_if(bgp, argv[idx_peer]->arg);
 | |
| 		if (!peer) {
 | |
| 			vty_out(vty, "%% Malformed address or name: %s\n",
 | |
| 				argv[idx_peer]->arg);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (peer_address_self_check(bgp, &su)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Can not configure the local system as neighbor\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		/* Disallow for dynamic neighbor. */
 | |
| 		peer = peer_lookup(bgp, &su);
 | |
| 		if (peer && peer_dynamic_neighbor(peer)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Operation not allowed on a dynamic neighbor\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, argv[idx_word]->arg);
 | |
| 	if (!group) {
 | |
| 		vty_out(vty, "%% Configure the peer-group first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_group_bind(bgp, &su, peer, group, &as);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Member of the peer-group\n"
 | |
| 	     "Peer-group name\n")
 | |
| 
 | |
| DEFUN (no_neighbor_set_peer_group,
 | |
|        no_neighbor_set_peer_group_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Member of the peer-group\n"
 | |
|        "Peer-group name\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_peer = 2;
 | |
| 	int idx_word = 4;
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	struct peer_group *group;
 | |
| 
 | |
| 	peer = peer_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	group = peer_group_lookup(bgp, argv[idx_word]->arg);
 | |
| 	if (!group) {
 | |
| 		vty_out(vty, "%% Configure the peer-group first\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
 | |
| 		bgp_zebra_terminate_radv(peer->bgp, peer);
 | |
| 
 | |
| 	peer_notify_unconfig(peer);
 | |
| 	ret = peer_delete(peer);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Member of the peer-group\n"
 | |
| 	     "Peer-group name\n")
 | |
| 
 | |
| /* neighbor passive. */
 | |
| DEFUN (neighbor_passive,
 | |
|        neighbor_passive_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> passive",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Don't send open messages to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg, PEER_FLAG_PASSIVE);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_passive,
 | |
|        no_neighbor_passive_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> passive",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Don't send open messages to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg, PEER_FLAG_PASSIVE);
 | |
| }
 | |
| 
 | |
| /* neighbor shutdown. */
 | |
| DEFUN (neighbor_shutdown_msg,
 | |
|        neighbor_shutdown_msg_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown message MSG...",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Administratively shut down this neighbor\n"
 | |
|        "Add a shutdown message (RFC 8203)\n"
 | |
|        "Shutdown message\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	if (argc >= 5) {
 | |
| 		struct peer *peer =
 | |
| 			peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 		char *message;
 | |
| 
 | |
| 		if (!peer)
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		message = argv_concat(argv, argc, 4);
 | |
| 		peer_tx_shutdown_message_set(peer, message);
 | |
| 		XFREE(MTYPE_TMP, message);
 | |
| 	}
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg, PEER_FLAG_SHUTDOWN);
 | |
| }
 | |
| 
 | |
| ALIAS(neighbor_shutdown_msg, neighbor_shutdown_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown",
 | |
|       NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Administratively shut down this neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_shutdown_msg,
 | |
|        no_neighbor_shutdown_msg_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown message MSG...",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Administratively shut down this neighbor\n"
 | |
|        "Remove a shutdown message (RFC 8203)\n"
 | |
|        "Shutdown message\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_SHUTDOWN);
 | |
| }
 | |
| 
 | |
| ALIAS(no_neighbor_shutdown_msg, no_neighbor_shutdown_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown",
 | |
|       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Administratively shut down this neighbor\n")
 | |
| 
 | |
| DEFUN(neighbor_shutdown_rtt,
 | |
|       neighbor_shutdown_rtt_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt (1-65535) [count (1-255)]",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Administratively shut down this neighbor\n"
 | |
|       "Shutdown if round-trip-time is higher than expected\n"
 | |
|       "Round-trip-time in milliseconds\n"
 | |
|       "Specify the number of keepalives before shutdown\n"
 | |
|       "The number of keepalives with higher RTT to shutdown\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_rtt = 4;
 | |
| 	int idx_count = 0;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	peer->rtt_expected = strtol(argv[idx_rtt]->arg, NULL, 10);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "count", &idx_count))
 | |
| 		peer->rtt_keepalive_conf =
 | |
| 			strtol(argv[idx_count + 1]->arg, NULL, 10);
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_RTT_SHUTDOWN);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_shutdown_rtt,
 | |
|       no_neighbor_shutdown_rtt_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt [(1-65535) [count (1-255)]]",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Administratively shut down this neighbor\n"
 | |
|       "Shutdown if round-trip-time is higher than expected\n"
 | |
|       "Round-trip-time in milliseconds\n"
 | |
|       "Specify the number of keepalives before shutdown\n"
 | |
|       "The number of keepalives with higher RTT to shutdown\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	peer->rtt_expected = 0;
 | |
| 	peer->rtt_keepalive_conf = 1;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_RTT_SHUTDOWN);
 | |
| }
 | |
| 
 | |
| /* neighbor capability dynamic. */
 | |
| DEFUN (neighbor_capability_dynamic,
 | |
|        neighbor_capability_dynamic_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> capability dynamic",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise dynamic capability to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_DYNAMIC_CAPABILITY);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_capability_dynamic,
 | |
|        no_neighbor_capability_dynamic_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> capability dynamic",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise dynamic capability to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_DYNAMIC_CAPABILITY);
 | |
| }
 | |
| 
 | |
| /* neighbor dont-capability-negotiate */
 | |
| DEFUN (neighbor_dont_capability_negotiate,
 | |
|        neighbor_dont_capability_negotiate_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> dont-capability-negotiate",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Do not perform capability negotiation\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_DONT_CAPABILITY);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_dont_capability_negotiate,
 | |
|        no_neighbor_dont_capability_negotiate_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> dont-capability-negotiate",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Do not perform capability negotiation\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_DONT_CAPABILITY);
 | |
| }
 | |
| 
 | |
| /* neighbor capability extended next hop encoding */
 | |
| DEFUN (neighbor_capability_enhe,
 | |
|        neighbor_capability_enhe_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> capability extended-nexthop",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise extended next-hop capability to the peer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (peer && peer->conf_if)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_CAPABILITY_ENHE);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_capability_enhe,
 | |
|        no_neighbor_capability_enhe_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> capability extended-nexthop",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise extended next-hop capability to the peer\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (peer && peer->conf_if) {
 | |
| 		vty_out(vty,
 | |
| 			"Peer %s cannot have capability extended-nexthop turned off\n",
 | |
| 			argv[idx_peer]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_CAPABILITY_ENHE);
 | |
| }
 | |
| 
 | |
| /* neighbor capability software-version */
 | |
| DEFPY(neighbor_capability_software_version,
 | |
|       neighbor_capability_software_version_cmd,
 | |
|       "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor capability software-version",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Advertise capability to the peer\n"
 | |
|       "Advertise Software Version capability to the peer\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (peer && peer->conf_if)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	if (no)
 | |
| 		return peer_flag_unset_vty(vty, neighbor,
 | |
| 					   PEER_FLAG_CAPABILITY_SOFT_VERSION);
 | |
| 	else
 | |
| 		return peer_flag_set_vty(vty, neighbor,
 | |
| 					 PEER_FLAG_CAPABILITY_SOFT_VERSION);
 | |
| }
 | |
| 
 | |
| static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str,
 | |
| 				   afi_t afi, safi_t safi, uint64_t flag,
 | |
| 				   int set)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (set)
 | |
| 		ret = peer_af_flag_set(peer, afi, safi, flag);
 | |
| 	else
 | |
| 		ret = peer_af_flag_unset(peer, afi, safi, flag);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_af_flag_set_vty(struct vty *vty, const char *peer_str,
 | |
| 				afi_t afi, safi_t safi, uint64_t flag)
 | |
| {
 | |
| 	return peer_af_flag_modify_vty(vty, peer_str, afi, safi, flag, 1);
 | |
| }
 | |
| 
 | |
| static int peer_af_flag_unset_vty(struct vty *vty, const char *peer_str,
 | |
| 				  afi_t afi, safi_t safi, uint64_t flag)
 | |
| {
 | |
| 	return peer_af_flag_modify_vty(vty, peer_str, afi, safi, flag, 0);
 | |
| }
 | |
| 
 | |
| /* neighbor capability orf prefix-list. */
 | |
| DEFUN (neighbor_capability_orf_prefix,
 | |
|        neighbor_capability_orf_prefix_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise ORF capability to the peer\n"
 | |
|        "Advertise prefixlist ORF capability to this neighbor\n"
 | |
|        "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
 | |
|        "Capability to RECEIVE the ORF from this neighbor\n"
 | |
|        "Capability to SEND the ORF to this neighbor\n")
 | |
| {
 | |
| 	int idx_send_recv = 5;
 | |
| 	char *peer_str = argv[1]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "send"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_ORF_PREFIX_SM);
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "receive"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_ORF_PREFIX_RM);
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "both"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_ORF_PREFIX_SM)
 | |
| 		       | peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_ORF_PREFIX_RM);
 | |
| 
 | |
| 	return CMD_WARNING_CONFIG_FAILED;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_capability_orf_prefix,
 | |
| 	neighbor_capability_orf_prefix_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Advertise capability to the peer\n"
 | |
| 	"Advertise ORF capability to the peer\n"
 | |
| 	"Advertise prefixlist ORF capability to this neighbor\n"
 | |
| 	"Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
 | |
| 	"Capability to RECEIVE the ORF from this neighbor\n"
 | |
| 	"Capability to SEND the ORF to this neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_capability_orf_prefix,
 | |
|        no_neighbor_capability_orf_prefix_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Advertise capability to the peer\n"
 | |
|        "Advertise ORF capability to the peer\n"
 | |
|        "Advertise prefixlist ORF capability to this neighbor\n"
 | |
|        "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
 | |
|        "Capability to RECEIVE the ORF from this neighbor\n"
 | |
|        "Capability to SEND the ORF to this neighbor\n")
 | |
| {
 | |
| 	int idx_send_recv = 6;
 | |
| 	char *peer_str = argv[2]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "send"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_ORF_PREFIX_SM);
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "receive"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_ORF_PREFIX_RM);
 | |
| 
 | |
| 	if (strmatch(argv[idx_send_recv]->text, "both"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_ORF_PREFIX_SM)
 | |
| 		       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 						PEER_FLAG_ORF_PREFIX_RM);
 | |
| 
 | |
| 	return CMD_WARNING_CONFIG_FAILED;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_capability_orf_prefix,
 | |
| 	no_neighbor_capability_orf_prefix_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Advertise capability to the peer\n"
 | |
| 	"Advertise ORF capability to the peer\n"
 | |
| 	"Advertise prefixlist ORF capability to this neighbor\n"
 | |
| 	"Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
 | |
| 	"Capability to RECEIVE the ORF from this neighbor\n"
 | |
| 	"Capability to SEND the ORF to this neighbor\n")
 | |
| 
 | |
| /* neighbor next-hop-self. */
 | |
| DEFUN (neighbor_nexthop_self,
 | |
|        neighbor_nexthop_self_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Disable the next hop calculation for this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty), PEER_FLAG_NEXTHOP_SELF);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_nexthop_self, neighbor_nexthop_self_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n")
 | |
| 
 | |
| /* neighbor next-hop-self. */
 | |
| DEFUN (neighbor_nexthop_self_force,
 | |
|        neighbor_nexthop_self_force_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Disable the next hop calculation for this neighbor\n"
 | |
|        "Set the next hop to self for reflected routes\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_FORCE_NEXTHOP_SELF);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_nexthop_self_force,
 | |
| 	     neighbor_nexthop_self_force_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n"
 | |
| 	     "Set the next hop to self for reflected routes\n")
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_nexthop_self_force,
 | |
| 	     neighbor_nexthop_self_all_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n"
 | |
| 	     "Set the next hop to self for reflected routes\n")
 | |
| 
 | |
| DEFUN (no_neighbor_nexthop_self,
 | |
|        no_neighbor_nexthop_self_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Disable the next hop calculation for this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_NEXTHOP_SELF);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_nexthop_self, no_neighbor_nexthop_self_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_nexthop_self_force,
 | |
|        no_neighbor_nexthop_self_force_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Disable the next hop calculation for this neighbor\n"
 | |
|        "Set the next hop to self for reflected routes\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_FORCE_NEXTHOP_SELF);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_nexthop_self_force,
 | |
| 	     no_neighbor_nexthop_self_force_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n"
 | |
| 	     "Set the next hop to self for reflected routes\n")
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_nexthop_self_force,
 | |
| 	     no_neighbor_nexthop_self_all_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Disable the next hop calculation for this neighbor\n"
 | |
| 	     "Set the next hop to self for reflected routes\n")
 | |
| 
 | |
| /* neighbor as-override */
 | |
| DEFUN (neighbor_as_override,
 | |
|        neighbor_as_override_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Override ASNs in outbound updates if aspath equals remote-as\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty), PEER_FLAG_AS_OVERRIDE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_as_override, neighbor_as_override_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Override ASNs in outbound updates if aspath equals remote-as\n")
 | |
| 
 | |
| DEFUN (no_neighbor_as_override,
 | |
|        no_neighbor_as_override_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Override ASNs in outbound updates if aspath equals remote-as\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_AS_OVERRIDE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_as_override, no_neighbor_as_override_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Override ASNs in outbound updates if aspath equals remote-as\n")
 | |
| 
 | |
| /* neighbor remove-private-AS. */
 | |
| DEFUN (neighbor_remove_private_as,
 | |
|        neighbor_remove_private_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_remove_private_as, neighbor_remove_private_as_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n")
 | |
| 
 | |
| DEFUN (neighbor_remove_private_as_all,
 | |
|        neighbor_remove_private_as_all_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Apply to all AS numbers\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_remove_private_as_all,
 | |
| 	     neighbor_remove_private_as_all_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n"
 | |
| 	     "Apply to all AS numbers\n")
 | |
| 
 | |
| DEFUN (neighbor_remove_private_as_replace_as,
 | |
|        neighbor_remove_private_as_replace_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Replace private ASNs with our ASN in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_remove_private_as_replace_as,
 | |
| 	     neighbor_remove_private_as_replace_as_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n"
 | |
| 	     "Replace private ASNs with our ASN in outbound updates\n")
 | |
| 
 | |
| DEFUN (neighbor_remove_private_as_all_replace_as,
 | |
|        neighbor_remove_private_as_all_replace_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Apply to all AS numbers\n"
 | |
|        "Replace private ASNs with our ASN in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_remove_private_as_all_replace_as,
 | |
| 	neighbor_remove_private_as_all_replace_as_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Remove private ASNs in outbound updates\n"
 | |
| 	"Apply to all AS numbers\n"
 | |
| 	"Replace private ASNs with our ASN in outbound updates\n")
 | |
| 
 | |
| DEFUN (no_neighbor_remove_private_as,
 | |
|        no_neighbor_remove_private_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_REMOVE_PRIVATE_AS);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_remove_private_as,
 | |
| 	     no_neighbor_remove_private_as_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n")
 | |
| 
 | |
| DEFUN (no_neighbor_remove_private_as_all,
 | |
|        no_neighbor_remove_private_as_all_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Apply to all AS numbers\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_remove_private_as_all,
 | |
| 	     no_neighbor_remove_private_as_all_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n"
 | |
| 	     "Apply to all AS numbers\n")
 | |
| 
 | |
| DEFUN (no_neighbor_remove_private_as_replace_as,
 | |
|        no_neighbor_remove_private_as_replace_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Replace private ASNs with our ASN in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_remove_private_as_replace_as,
 | |
| 	     no_neighbor_remove_private_as_replace_as_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Remove private ASNs in outbound updates\n"
 | |
| 	     "Replace private ASNs with our ASN in outbound updates\n")
 | |
| 
 | |
| DEFUN (no_neighbor_remove_private_as_all_replace_as,
 | |
|        no_neighbor_remove_private_as_all_replace_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Remove private ASNs in outbound updates\n"
 | |
|        "Apply to all AS numbers\n"
 | |
|        "Replace private ASNs with our ASN in outbound updates\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_remove_private_as_all_replace_as,
 | |
| 	no_neighbor_remove_private_as_all_replace_as_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Remove private ASNs in outbound updates\n"
 | |
| 	"Apply to all AS numbers\n"
 | |
| 	"Replace private ASNs with our ASN in outbound updates\n")
 | |
| 
 | |
| 
 | |
| /* neighbor send-community. */
 | |
| DEFUN (neighbor_send_community,
 | |
|        neighbor_send_community_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Send Community attribute to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_SEND_COMMUNITY);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_send_community, neighbor_send_community_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Send Community attribute to this neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_send_community,
 | |
|        no_neighbor_send_community_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Send Community attribute to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_SEND_COMMUNITY);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_send_community, no_neighbor_send_community_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Send Community attribute to this neighbor\n")
 | |
| 
 | |
| /* neighbor send-community extended. */
 | |
| DEFUN (neighbor_send_community_type,
 | |
|        neighbor_send_community_type_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Send Community attribute to this neighbor\n"
 | |
|        "Send Standard and Extended Community attributes\n"
 | |
|        "Send Standard, Large and Extended Community attributes\n"
 | |
|        "Send Extended Community attributes\n"
 | |
|        "Send Standard Community attributes\n"
 | |
|        "Send Large Community attributes\n")
 | |
| {
 | |
| 	const char *type = argv[argc - 1]->text;
 | |
| 	char *peer_str = argv[1]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (strmatch(type, "standard"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_SEND_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "extended"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_SEND_EXT_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "large"))
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_SEND_LARGE_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "both")) {
 | |
| 		return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_SEND_COMMUNITY)
 | |
| 		       | peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_SEND_EXT_COMMUNITY);
 | |
| 	}
 | |
| 	return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 				    PEER_FLAG_SEND_COMMUNITY)
 | |
| 	       | peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 				      PEER_FLAG_SEND_EXT_COMMUNITY)
 | |
| 	       | peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 				      PEER_FLAG_SEND_LARGE_COMMUNITY);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_send_community_type, neighbor_send_community_type_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Send Community attribute to this neighbor\n"
 | |
| 	"Send Standard and Extended Community attributes\n"
 | |
| 	"Send Standard, Large and Extended Community attributes\n"
 | |
| 	"Send Extended Community attributes\n"
 | |
| 	"Send Standard Community attributes\n"
 | |
| 	"Send Large Community attributes\n")
 | |
| 
 | |
| DEFUN (no_neighbor_send_community_type,
 | |
|        no_neighbor_send_community_type_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Send Community attribute to this neighbor\n"
 | |
|        "Send Standard and Extended Community attributes\n"
 | |
|        "Send Standard, Large and Extended Community attributes\n"
 | |
|        "Send Extended Community attributes\n"
 | |
|        "Send Standard Community attributes\n"
 | |
|        "Send Large Community attributes\n")
 | |
| {
 | |
| 	const char *type = argv[argc - 1]->text;
 | |
| 	char *peer_str = argv[2]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (strmatch(type, "standard"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_SEND_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "extended"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_SEND_EXT_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "large"))
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_SEND_LARGE_COMMUNITY);
 | |
| 
 | |
| 	if (strmatch(type, "both")) {
 | |
| 
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_SEND_COMMUNITY)
 | |
| 		       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 						PEER_FLAG_SEND_EXT_COMMUNITY);
 | |
| 	}
 | |
| 
 | |
| 	return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 				      PEER_FLAG_SEND_COMMUNITY)
 | |
| 	       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					PEER_FLAG_SEND_EXT_COMMUNITY)
 | |
| 	       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					PEER_FLAG_SEND_LARGE_COMMUNITY);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_send_community_type,
 | |
| 	no_neighbor_send_community_type_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Send Community attribute to this neighbor\n"
 | |
| 	"Send Standard and Extended Community attributes\n"
 | |
| 	"Send Standard, Large and Extended Community attributes\n"
 | |
| 	"Send Extended Community attributes\n"
 | |
| 	"Send Standard Community attributes\n"
 | |
| 	"Send Large Community attributes\n")
 | |
| 
 | |
| /* neighbor soft-reconfig. */
 | |
| DEFUN (neighbor_soft_reconfiguration,
 | |
|        neighbor_soft_reconfiguration_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Per neighbor soft reconfiguration\n"
 | |
|        "Allow inbound soft reconfiguration for this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_SOFT_RECONFIG);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_soft_reconfiguration,
 | |
| 	     neighbor_soft_reconfiguration_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Per neighbor soft reconfiguration\n"
 | |
| 	     "Allow inbound soft reconfiguration for this neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_soft_reconfiguration,
 | |
|        no_neighbor_soft_reconfiguration_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Per neighbor soft reconfiguration\n"
 | |
|        "Allow inbound soft reconfiguration for this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_SOFT_RECONFIG);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_soft_reconfiguration,
 | |
| 	     no_neighbor_soft_reconfiguration_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Per neighbor soft reconfiguration\n"
 | |
| 	     "Allow inbound soft reconfiguration for this neighbor\n")
 | |
| 
 | |
| DEFUN (neighbor_route_reflector_client,
 | |
|        neighbor_route_reflector_client_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure a neighbor as Route Reflector client\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_REFLECTOR_CLIENT);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_route_reflector_client,
 | |
| 	     neighbor_route_reflector_client_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Configure a neighbor as Route Reflector client\n")
 | |
| 
 | |
| DEFUN (no_neighbor_route_reflector_client,
 | |
|        no_neighbor_route_reflector_client_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure a neighbor as Route Reflector client\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_REFLECTOR_CLIENT);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_route_reflector_client,
 | |
| 	     no_neighbor_route_reflector_client_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Configure a neighbor as Route Reflector client\n")
 | |
| 
 | |
| /* neighbor route-server-client. */
 | |
| DEFUN (neighbor_route_server_client,
 | |
|        neighbor_route_server_client_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure a neighbor as Route Server client\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_RSERVER_CLIENT);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_route_server_client,
 | |
| 	     neighbor_route_server_client_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Configure a neighbor as Route Server client\n")
 | |
| 
 | |
| DEFUN (no_neighbor_route_server_client,
 | |
|        no_neighbor_route_server_client_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure a neighbor as Route Server client\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_RSERVER_CLIENT);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_route_server_client,
 | |
| 	     no_neighbor_route_server_client_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Configure a neighbor as Route Server client\n")
 | |
| 
 | |
| DEFUN (neighbor_nexthop_local_unchanged,
 | |
|        neighbor_nexthop_local_unchanged_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> nexthop-local unchanged",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure treatment of outgoing link-local nexthop attribute\n"
 | |
|        "Leave link-local nexthop unchanged for this peer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty),
 | |
| 				    PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_nexthop_local_unchanged,
 | |
|        no_neighbor_nexthop_local_unchanged_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> nexthop-local unchanged",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Configure treatment of outgoing link-local-nexthop attribute\n"
 | |
|        "Leave link-local nexthop unchanged for this peer\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				      bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				      PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_attr_unchanged,
 | |
|        neighbor_attr_unchanged_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged [{as-path|next-hop|med}]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP attribute is propagated unchanged to this neighbor\n"
 | |
|        "As-path attribute\n"
 | |
|        "Nexthop attribute\n"
 | |
|        "Med attribute\n")
 | |
| {
 | |
| 	int idx = 0;
 | |
| 	char *peer_str = argv[1]->arg;
 | |
| 	struct peer *peer;
 | |
| 	bool aspath = false;
 | |
| 	bool nexthop = false;
 | |
| 	bool med = false;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "as-path", &idx))
 | |
| 		aspath = true;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "next-hop", &idx))
 | |
| 		nexthop = true;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "med", &idx))
 | |
| 		med = true;
 | |
| 
 | |
| 	/* no flags means all of them! */
 | |
| 	if (!aspath && !nexthop && !med) {
 | |
| 		ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					   PEER_FLAG_AS_PATH_UNCHANGED);
 | |
| 		ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_NEXTHOP_UNCHANGED);
 | |
| 		ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 					    PEER_FLAG_MED_UNCHANGED);
 | |
| 	} else {
 | |
| 		if (!aspath) {
 | |
| 			if (peer_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_AS_PATH_UNCHANGED)) {
 | |
| 				ret |= peer_af_flag_unset_vty(
 | |
| 					vty, peer_str, afi, safi,
 | |
| 					PEER_FLAG_AS_PATH_UNCHANGED);
 | |
| 			}
 | |
| 		} else
 | |
| 			ret |= peer_af_flag_set_vty(
 | |
| 				vty, peer_str, afi, safi,
 | |
| 				PEER_FLAG_AS_PATH_UNCHANGED);
 | |
| 
 | |
| 		if (!nexthop) {
 | |
| 			if (peer_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_NEXTHOP_UNCHANGED)) {
 | |
| 				ret |= peer_af_flag_unset_vty(
 | |
| 					vty, peer_str, afi, safi,
 | |
| 					PEER_FLAG_NEXTHOP_UNCHANGED);
 | |
| 			}
 | |
| 		} else
 | |
| 			ret |= peer_af_flag_set_vty(
 | |
| 				vty, peer_str, afi, safi,
 | |
| 				PEER_FLAG_NEXTHOP_UNCHANGED);
 | |
| 
 | |
| 		if (!med) {
 | |
| 			if (peer_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_MED_UNCHANGED)) {
 | |
| 				ret |= peer_af_flag_unset_vty(
 | |
| 					vty, peer_str, afi, safi,
 | |
| 					PEER_FLAG_MED_UNCHANGED);
 | |
| 			}
 | |
| 		} else
 | |
| 			ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 						    PEER_FLAG_MED_UNCHANGED);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_attr_unchanged, neighbor_attr_unchanged_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged [{as-path|next-hop|med}]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"BGP attribute is propagated unchanged to this neighbor\n"
 | |
| 	"As-path attribute\n"
 | |
| 	"Nexthop attribute\n"
 | |
| 	"Med attribute\n")
 | |
| 
 | |
| DEFUN (no_neighbor_attr_unchanged,
 | |
|        no_neighbor_attr_unchanged_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged [{as-path|next-hop|med}]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP attribute is propagated unchanged to this neighbor\n"
 | |
|        "As-path attribute\n"
 | |
|        "Nexthop attribute\n"
 | |
|        "Med attribute\n")
 | |
| {
 | |
| 	int idx = 0;
 | |
| 	char *peer_str = argv[2]->arg;
 | |
| 	struct peer *peer;
 | |
| 	bool aspath = false;
 | |
| 	bool nexthop = false;
 | |
| 	bool med = false;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "as-path", &idx))
 | |
| 		aspath = true;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "next-hop", &idx))
 | |
| 		nexthop = true;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	if (argv_find(argv, argc, "med", &idx))
 | |
| 		med = true;
 | |
| 
 | |
| 	if (!aspath && !nexthop && !med) // no flags means all of them!
 | |
| 		return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_AS_PATH_UNCHANGED)
 | |
| 		       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 						PEER_FLAG_NEXTHOP_UNCHANGED)
 | |
| 		       | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 						PEER_FLAG_MED_UNCHANGED);
 | |
| 
 | |
| 	if (aspath)
 | |
| 		ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_AS_PATH_UNCHANGED);
 | |
| 
 | |
| 	if (nexthop)
 | |
| 		ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_NEXTHOP_UNCHANGED);
 | |
| 
 | |
| 	if (med)
 | |
| 		ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 					      PEER_FLAG_MED_UNCHANGED);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_attr_unchanged, no_neighbor_attr_unchanged_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged [{as-path|next-hop|med}]",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"BGP attribute is propagated unchanged to this neighbor\n"
 | |
| 	"As-path attribute\n"
 | |
| 	"Nexthop attribute\n"
 | |
| 	"Med attribute\n")
 | |
| 
 | |
| /* EBGP multihop configuration. */
 | |
| static int peer_ebgp_multihop_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				      const char *ttl_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	unsigned int ttl;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (peer->conf_if)
 | |
| 		return bgp_vty_return(vty, BGP_ERR_INVALID_FOR_DIRECT_PEER);
 | |
| 
 | |
| 	if (!ttl_str)
 | |
| 		ttl = MAXTTL;
 | |
| 	else
 | |
| 		ttl = strtoul(ttl_str, NULL, 10);
 | |
| 
 | |
| 	return bgp_vty_return(vty, peer_ebgp_multihop_set(peer, ttl));
 | |
| }
 | |
| 
 | |
| static int peer_ebgp_multihop_unset_vty(struct vty *vty, const char *ip_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return bgp_vty_return(vty, peer_ebgp_multihop_unset(peer));
 | |
| }
 | |
| 
 | |
| /* neighbor ebgp-multihop. */
 | |
| DEFUN (neighbor_ebgp_multihop,
 | |
|        neighbor_ebgp_multihop_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> ebgp-multihop",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Allow EBGP neighbors not on directly connected networks\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_ebgp_multihop_set_vty(vty, argv[idx_peer]->arg, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_ebgp_multihop_ttl,
 | |
|        neighbor_ebgp_multihop_ttl_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> ebgp-multihop (1-255)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Allow EBGP neighbors not on directly connected networks\n"
 | |
|        "maximum hop count\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	return peer_ebgp_multihop_set_vty(vty, argv[idx_peer]->arg,
 | |
| 					  argv[idx_number]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_ebgp_multihop,
 | |
|        no_neighbor_ebgp_multihop_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> ebgp-multihop [(1-255)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Allow EBGP neighbors not on directly connected networks\n"
 | |
|        "maximum hop count\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_ebgp_multihop_unset_vty(vty, argv[idx_peer]->arg);
 | |
| }
 | |
| 
 | |
| DEFPY (neighbor_aigp,
 | |
|        neighbor_aigp_cmd,
 | |
|        "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor aigp",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enable send and receive of the AIGP attribute per neighbor\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (no)
 | |
| 		return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AIGP);
 | |
| 	else
 | |
| 		return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AIGP);
 | |
| }
 | |
| 
 | |
| static uint8_t get_role_by_name(const char *role_str)
 | |
| {
 | |
| 	if (strncmp(role_str, "peer", 2) == 0)
 | |
| 		return ROLE_PEER;
 | |
| 	if (strncmp(role_str, "provider", 2) == 0)
 | |
| 		return ROLE_PROVIDER;
 | |
| 	if (strncmp(role_str, "customer", 2) == 0)
 | |
| 		return ROLE_CUSTOMER;
 | |
| 	if (strncmp(role_str, "rs-server", 4) == 0)
 | |
| 		return ROLE_RS_SERVER;
 | |
| 	if (strncmp(role_str, "rs-client", 4) == 0)
 | |
| 		return ROLE_RS_CLIENT;
 | |
| 	return ROLE_UNDEFINED;
 | |
| }
 | |
| 
 | |
| static int peer_role_set_vty(struct vty *vty, const char *ip_str,
 | |
| 			     const char *role_str, bool strict_mode)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	uint8_t role = get_role_by_name(role_str);
 | |
| 
 | |
| 	if (role == ROLE_UNDEFINED)
 | |
| 		return bgp_vty_return(vty, BGP_ERR_INVALID_ROLE_NAME);
 | |
| 	return bgp_vty_return(vty, peer_role_set(peer, role, strict_mode));
 | |
| }
 | |
| 
 | |
| static int peer_role_unset_vty(struct vty *vty, const char *ip_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	return bgp_vty_return(vty, peer_role_unset(peer));
 | |
| }
 | |
| 
 | |
| DEFPY(neighbor_role,
 | |
|       neighbor_role_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer>",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Set session role\n"
 | |
|       ROLE_STR)
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_role = 3;
 | |
| 
 | |
| 	return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg,
 | |
| 				 false);
 | |
| }
 | |
| 
 | |
| DEFPY(neighbor_role_strict,
 | |
|       neighbor_role_strict_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> strict-mode",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Set session role\n"
 | |
|       ROLE_STR
 | |
|       "Use additional restriction on peer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_role = 3;
 | |
| 
 | |
| 	return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg,
 | |
| 				 true);
 | |
| }
 | |
| 
 | |
| DEFPY(no_neighbor_role,
 | |
|       no_neighbor_role_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> [strict-mode]",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Set session role\n"
 | |
|       ROLE_STR
 | |
|       "Use additional restriction on peer\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_role_unset_vty(vty, argv[idx_peer]->arg);
 | |
| }
 | |
| 
 | |
| /* disable-connected-check */
 | |
| DEFUN (neighbor_disable_connected_check,
 | |
|        neighbor_disable_connected_check_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> <disable-connected-check|enforce-multihop>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "one-hop away EBGP peer using loopback address\n"
 | |
|        "Enforce EBGP neighbors perform multihop\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_DISABLE_CONNECTED_CHECK);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_disable_connected_check,
 | |
|        no_neighbor_disable_connected_check_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> <disable-connected-check|enforce-multihop>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "one-hop away EBGP peer using loopback address\n"
 | |
|        "Enforce EBGP neighbors perform multihop\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_DISABLE_CONNECTED_CHECK);
 | |
| }
 | |
| 
 | |
| /* disable-link-bw-encoding-ieee */
 | |
| DEFUN(neighbor_disable_link_bw_encoding_ieee,
 | |
|       neighbor_disable_link_bw_encoding_ieee_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> disable-link-bw-encoding-ieee",
 | |
|       NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Disable IEEE floating-point encoding for extended community bandwidth\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_disable_link_bw_encoding_ieee,
 | |
|       no_neighbor_disable_link_bw_encoding_ieee_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> disable-link-bw-encoding-ieee",
 | |
|       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Disable IEEE floating-point encoding for extended community bandwidth\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE);
 | |
| }
 | |
| 
 | |
| /* extended-optional-parameters */
 | |
| DEFUN(neighbor_extended_optional_parameters,
 | |
|       neighbor_extended_optional_parameters_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters",
 | |
|       NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Force the extended optional parameters format for OPEN messages\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_EXTENDED_OPT_PARAMS);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_extended_optional_parameters,
 | |
|       no_neighbor_extended_optional_parameters_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters",
 | |
|       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Force the extended optional parameters format for OPEN messages\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_EXTENDED_OPT_PARAMS);
 | |
| }
 | |
| 
 | |
| /* enforce-first-as */
 | |
| DEFUN (neighbor_enforce_first_as,
 | |
|        neighbor_enforce_first_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> enforce-first-as",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enforce the first AS for EBGP routes\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_ENFORCE_FIRST_AS);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_enforce_first_as,
 | |
|        no_neighbor_enforce_first_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> enforce-first-as",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enforce the first AS for EBGP routes\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_ENFORCE_FIRST_AS);
 | |
| }
 | |
| 
 | |
| 
 | |
| DEFUN (neighbor_description,
 | |
|        neighbor_description_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> description LINE...",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Neighbor specific description\n"
 | |
|        "Up to 80 characters describing this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_line = 3;
 | |
| 	struct peer *peer;
 | |
| 	char *str;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	str = argv_concat(argv, argc, idx_line);
 | |
| 
 | |
| 	peer_description_set(peer, str);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_description,
 | |
|        no_neighbor_description_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> description",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Neighbor specific description\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	peer_description_unset(peer);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_neighbor_description, no_neighbor_description_comment_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> description LINE...",
 | |
|       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "Neighbor specific description\n"
 | |
|       "Up to 80 characters describing this neighbor\n")
 | |
| 
 | |
| /* Neighbor update-source. */
 | |
| static int peer_update_source_vty(struct vty *vty, const char *peer_str,
 | |
| 				  const char *source_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	struct prefix p;
 | |
| 	union sockunion su;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (peer->conf_if)
 | |
| 		return CMD_WARNING;
 | |
| 
 | |
| 	if (source_str) {
 | |
| 		if (str2sockunion(source_str, &su) == 0)
 | |
| 			peer_update_source_addr_set(peer, &su);
 | |
| 		else {
 | |
| 			if (str2prefix(source_str, &p)) {
 | |
| 				vty_out(vty,
 | |
| 					"%% Invalid update-source, remove prefix length \n");
 | |
| 				return CMD_WARNING_CONFIG_FAILED;
 | |
| 			} else
 | |
| 				peer_update_source_if_set(peer, source_str);
 | |
| 		}
 | |
| 	} else
 | |
| 		peer_update_source_unset(peer);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| #define BGP_UPDATE_SOURCE_HELP_STR                                             \
 | |
| 	"IPv4 address\n"                                                       \
 | |
| 	"IPv6 address\n"                                                       \
 | |
| 	"Interface name (requires zebra to be running)\n"
 | |
| 
 | |
| DEFUN (neighbor_update_source,
 | |
|        neighbor_update_source_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> update-source <A.B.C.D|X:X::X:X|WORD>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Source of routing updates\n"
 | |
|        BGP_UPDATE_SOURCE_HELP_STR)
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_peer_2 = 3;
 | |
| 	return peer_update_source_vty(vty, argv[idx_peer]->arg,
 | |
| 				      argv[idx_peer_2]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_update_source,
 | |
|        no_neighbor_update_source_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> update-source [<A.B.C.D|X:X::X:X|WORD>]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Source of routing updates\n"
 | |
|        BGP_UPDATE_SOURCE_HELP_STR)
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_update_source_vty(vty, argv[idx_peer]->arg, NULL);
 | |
| }
 | |
| 
 | |
| static int peer_default_originate_set_vty(struct vty *vty, const char *peer_str,
 | |
| 					  afi_t afi, safi_t safi,
 | |
| 					  const char *rmap, int set)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	struct route_map *route_map = NULL;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (set) {
 | |
| 		if (rmap)
 | |
| 			route_map = route_map_lookup_warn_noexist(vty, rmap);
 | |
| 		ret = peer_default_originate_set(peer, afi, safi,
 | |
| 						 rmap, route_map);
 | |
| 	} else
 | |
| 		ret = peer_default_originate_unset(peer, afi, safi);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| /* neighbor default-originate. */
 | |
| DEFUN (neighbor_default_originate,
 | |
|        neighbor_default_originate_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Originate default route to this neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_default_originate_set_vty(vty, argv[idx_peer]->arg,
 | |
| 					      bgp_node_afi(vty),
 | |
| 					      bgp_node_safi(vty), NULL, 1);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_default_originate, neighbor_default_originate_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Originate default route to this neighbor\n")
 | |
| 
 | |
| DEFUN (neighbor_default_originate_rmap,
 | |
|        neighbor_default_originate_rmap_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate route-map RMAP_NAME",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Originate default route to this neighbor\n"
 | |
|        "Route-map to specify criteria to originate default\n"
 | |
|        "route-map name\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 4;
 | |
| 	return peer_default_originate_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_word]->arg, 1);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_default_originate_rmap,
 | |
| 	neighbor_default_originate_rmap_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> default-originate route-map RMAP_NAME",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Originate default route to this neighbor\n"
 | |
| 	"Route-map to specify criteria to originate default\n"
 | |
| 	"route-map name\n")
 | |
| 
 | |
| DEFUN (no_neighbor_default_originate,
 | |
|        no_neighbor_default_originate_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> default-originate [route-map RMAP_NAME]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Originate default route to this neighbor\n"
 | |
|        "Route-map to specify criteria to originate default\n"
 | |
|        "route-map name\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_default_originate_set_vty(vty, argv[idx_peer]->arg,
 | |
| 					      bgp_node_afi(vty),
 | |
| 					      bgp_node_safi(vty), NULL, 0);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_default_originate, no_neighbor_default_originate_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> default-originate [route-map RMAP_NAME]",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Originate default route to this neighbor\n"
 | |
| 	"Route-map to specify criteria to originate default\n"
 | |
| 	"route-map name\n")
 | |
| 
 | |
| 
 | |
| /* Set neighbor's BGP port.  */
 | |
| static int peer_port_vty(struct vty *vty, const char *ip_str, int afi,
 | |
| 			 const char *port_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	uint16_t port;
 | |
| 	struct servent *sp;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!port_str) {
 | |
| 		sp = getservbyname("bgp", "tcp");
 | |
| 		port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs(sp->s_port);
 | |
| 	} else {
 | |
| 		port = strtoul(port_str, NULL, 10);
 | |
| 	}
 | |
| 
 | |
| 	peer_port_set(peer, port);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Set specified peer's BGP port.  */
 | |
| DEFUN (neighbor_port,
 | |
|        neighbor_port_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> port (0-65535)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Neighbor's BGP port\n"
 | |
|        "TCP port number\n")
 | |
| {
 | |
| 	int idx_ip = 1;
 | |
| 	int idx_number = 3;
 | |
| 	return peer_port_vty(vty, argv[idx_ip]->arg, AFI_IP,
 | |
| 			     argv[idx_number]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_port,
 | |
|        no_neighbor_port_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> port [(0-65535)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Neighbor's BGP port\n"
 | |
|        "TCP port number\n")
 | |
| {
 | |
| 	int idx_ip = 2;
 | |
| 	return peer_port_vty(vty, argv[idx_ip]->arg, AFI_IP, NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* neighbor weight. */
 | |
| static int peer_weight_set_vty(struct vty *vty, const char *ip_str, afi_t afi,
 | |
| 			       safi_t safi, const char *weight_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	unsigned long weight;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	weight = strtoul(weight_str, NULL, 10);
 | |
| 
 | |
| 	ret = peer_weight_set(peer, afi, safi, weight);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_weight_unset_vty(struct vty *vty, const char *ip_str, afi_t afi,
 | |
| 				 safi_t safi)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_weight_unset(peer, afi, safi);
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_weight,
 | |
|        neighbor_weight_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> weight (0-65535)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set default weight for routes from this neighbor\n"
 | |
|        "default weight\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	return peer_weight_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				   bgp_node_safi(vty), argv[idx_number]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_weight, neighbor_weight_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> weight (0-65535)",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Set default weight for routes from this neighbor\n"
 | |
| 	     "default weight\n")
 | |
| 
 | |
| DEFUN (no_neighbor_weight,
 | |
|        no_neighbor_weight_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> weight [(0-65535)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set default weight for routes from this neighbor\n"
 | |
|        "default weight\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_weight_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				     bgp_node_afi(vty), bgp_node_safi(vty));
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_weight, no_neighbor_weight_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> weight [(0-65535)]",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Set default weight for routes from this neighbor\n"
 | |
| 	     "default weight\n")
 | |
| 
 | |
| 
 | |
| /* Override capability negotiation. */
 | |
| DEFUN (neighbor_override_capability,
 | |
|        neighbor_override_capability_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> override-capability",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Override capability negotiation result\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_OVERRIDE_CAPABILITY);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_override_capability,
 | |
|        no_neighbor_override_capability_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> override-capability",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Override capability negotiation result\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_OVERRIDE_CAPABILITY);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_strict_capability,
 | |
|        neighbor_strict_capability_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Strict capability negotiation match\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 
 | |
| 	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				 PEER_FLAG_STRICT_CAP_MATCH);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_strict_capability,
 | |
|        no_neighbor_strict_capability_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Strict capability negotiation match\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				   PEER_FLAG_STRICT_CAP_MATCH);
 | |
| }
 | |
| 
 | |
| static int peer_timers_set_vty(struct vty *vty, const char *ip_str,
 | |
| 			       const char *keep_str, const char *hold_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	uint32_t keepalive;
 | |
| 	uint32_t holdtime;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	keepalive = strtoul(keep_str, NULL, 10);
 | |
| 	holdtime = strtoul(hold_str, NULL, 10);
 | |
| 
 | |
| 	ret = peer_timers_set(peer, keepalive, holdtime);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_timers_unset_vty(struct vty *vty, const char *ip_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_timers_unset(peer);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_timers,
 | |
|        neighbor_timers_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> timers (0-65535) (0-65535)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "Keepalive interval\n"
 | |
|        "Holdtime\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_number_2 = 4;
 | |
| 	return peer_timers_set_vty(vty, argv[idx_peer]->arg,
 | |
| 				   argv[idx_number]->arg,
 | |
| 				   argv[idx_number_2]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_timers,
 | |
|        no_neighbor_timers_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> timers [(0-65535) (0-65535)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "Keepalive interval\n"
 | |
|        "Holdtime\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_timers_unset_vty(vty, argv[idx_peer]->arg);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int peer_timers_connect_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				       const char *time_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	uint32_t connect;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	connect = strtoul(time_str, NULL, 10);
 | |
| 
 | |
| 	ret = peer_timers_connect_set(peer, connect);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_timers_connect_unset_vty(struct vty *vty, const char *ip_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_timers_connect_unset(peer);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_timers_connect,
 | |
|        neighbor_timers_connect_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> timers connect (1-65535)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "BGP connect timer\n"
 | |
|        "Connect timer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 4;
 | |
| 	return peer_timers_connect_set_vty(vty, argv[idx_peer]->arg,
 | |
| 					   argv[idx_number]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_timers_connect,
 | |
|        no_neighbor_timers_connect_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> timers connect [(1-65535)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "BGP connect timer\n"
 | |
|        "Connect timer\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_timers_connect_unset_vty(vty, argv[idx_peer]->arg);
 | |
| }
 | |
| 
 | |
| DEFPY (neighbor_timers_delayopen,
 | |
|        neighbor_timers_delayopen_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor timers delayopen (1-240)$interval",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "RFC 4271 DelayOpenTimer\n"
 | |
|        "DelayOpenTime timer interval\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!interval) {
 | |
| 		if (peer_timers_delayopen_unset(peer))
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 	} else {
 | |
| 		if (peer_timers_delayopen_set(peer, interval))
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_neighbor_timers_delayopen,
 | |
|        no_neighbor_timers_delayopen_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor timers delayopen [(0-65535)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP per neighbor timers\n"
 | |
|        "RFC 4271 DelayOpenTimer\n"
 | |
|        "DelayOpenTime timer interval\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (peer_timers_delayopen_unset(peer))
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int peer_advertise_interval_vty(struct vty *vty, const char *ip_str,
 | |
| 				       const char *time_str, int set)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	uint32_t routeadv = 0;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (time_str)
 | |
| 		routeadv = strtoul(time_str, NULL, 10);
 | |
| 
 | |
| 	if (set)
 | |
| 		ret = peer_advertise_interval_set(peer, routeadv);
 | |
| 	else
 | |
| 		ret = peer_advertise_interval_unset(peer);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_advertise_interval,
 | |
|        neighbor_advertise_interval_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> advertisement-interval (0-600)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Minimum interval between sending BGP routing updates\n"
 | |
|        "time in seconds\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	return peer_advertise_interval_vty(vty, argv[idx_peer]->arg,
 | |
| 					   argv[idx_number]->arg, 1);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_advertise_interval,
 | |
|        no_neighbor_advertise_interval_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> advertisement-interval [(0-600)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Minimum interval between sending BGP routing updates\n"
 | |
|        "time in seconds\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_advertise_interval_vty(vty, argv[idx_peer]->arg, NULL, 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Time to wait before processing route-map updates */
 | |
| DEFUN (bgp_set_route_map_delay_timer,
 | |
|        bgp_set_route_map_delay_timer_cmd,
 | |
|        "bgp route-map delay-timer (0-600)",
 | |
|        SET_STR
 | |
|        "BGP route-map delay timer\n"
 | |
|        "Time in secs to wait before processing route-map changes\n"
 | |
|        "0 disables the timer, no route updates happen when route-maps change\n")
 | |
| {
 | |
| 	int idx_number = 3;
 | |
| 	uint32_t rmap_delay_timer;
 | |
| 
 | |
| 	if (argv[idx_number]->arg) {
 | |
| 		rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 		bm->rmap_update_timer = rmap_delay_timer;
 | |
| 
 | |
| 		/* if the dynamic update handling is being disabled, and a timer
 | |
| 		 * is
 | |
| 		 * running, stop the timer and act as if the timer has already
 | |
| 		 * fired.
 | |
| 		 */
 | |
| 		if (!rmap_delay_timer && bm->t_rmap_update) {
 | |
| 			EVENT_OFF(bm->t_rmap_update);
 | |
| 			event_execute(bm->master, bgp_route_map_update_timer,
 | |
| 				      NULL, 0);
 | |
| 		}
 | |
| 		return CMD_SUCCESS;
 | |
| 	} else {
 | |
| 		vty_out(vty, "%% BGP invalid route-map delay-timer\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_set_route_map_delay_timer,
 | |
|        no_bgp_set_route_map_delay_timer_cmd,
 | |
|        "no bgp route-map delay-timer [(0-600)]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Default BGP route-map delay timer\n"
 | |
|        "Reset to default time to wait for processing route-map changes\n"
 | |
|        "0 disables the timer, no route updates happen when route-maps change\n")
 | |
| {
 | |
| 
 | |
| 	bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* neighbor interface */
 | |
| static int peer_interface_vty(struct vty *vty, const char *ip_str,
 | |
| 			      const char *str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_lookup_vty(vty, ip_str);
 | |
| 	if (!peer || peer->conf_if) {
 | |
| 		vty_out(vty, "%% BGP invalid peer %s\n", ip_str);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (str)
 | |
| 		peer_interface_set(peer, str);
 | |
| 	else
 | |
| 		peer_interface_unset(peer);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_interface,
 | |
|        neighbor_interface_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X> interface WORD",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR
 | |
|        "Interface\n"
 | |
|        "Interface name\n")
 | |
| {
 | |
| 	int idx_ip = 1;
 | |
| 	int idx_word = 3;
 | |
| 
 | |
| 	return peer_interface_vty(vty, argv[idx_ip]->arg, argv[idx_word]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_interface,
 | |
|        no_neighbor_interface_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X> interface WORD",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR
 | |
|        "Interface\n"
 | |
|        "Interface name\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 
 | |
| 	return peer_interface_vty(vty, argv[idx_peer]->arg, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_distribute_list,
 | |
|        neighbor_distribute_list_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Filter updates to/from this neighbor\n"
 | |
|        "IP Access-list name\n"
 | |
|        "Filter incoming updates\n"
 | |
|        "Filter outgoing updates\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_acl = 3;
 | |
| 	int direct, ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	const char *pstr = argv[idx_peer]->arg;
 | |
| 	const char *acl = argv[idx_acl]->arg;
 | |
| 	const char *inout = argv[argc - 1]->text;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, pstr);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	direct = strmatch(inout, "in") ? FILTER_IN : FILTER_OUT;
 | |
| 	ret = peer_distribute_set(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  direct, acl);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_distribute_list, neighbor_distribute_list_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Filter updates to/from this neighbor\n"
 | |
| 	"IP Access-list name\n"
 | |
| 	"Filter incoming updates\n"
 | |
| 	"Filter outgoing updates\n")
 | |
| 
 | |
| DEFUN (no_neighbor_distribute_list,
 | |
|        no_neighbor_distribute_list_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Filter updates to/from this neighbor\n"
 | |
|        "IP Access-list name\n"
 | |
|        "Filter incoming updates\n"
 | |
|        "Filter outgoing updates\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int direct, ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	const char *pstr = argv[idx_peer]->arg;
 | |
| 	const char *inout = argv[argc - 1]->text;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, pstr);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	direct = strmatch(inout, "in") ? FILTER_IN : FILTER_OUT;
 | |
| 	ret = peer_distribute_unset(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				    direct);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_distribute_list, no_neighbor_distribute_list_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Filter updates to/from this neighbor\n"
 | |
| 	"IP Access-list name\n"
 | |
| 	"Filter incoming updates\n"
 | |
| 	"Filter outgoing updates\n")
 | |
| 
 | |
| /* Set prefix list to the peer. */
 | |
| static int peer_prefix_list_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				    afi_t afi, safi_t safi,
 | |
| 				    const char *name_str,
 | |
| 				    const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	int direct = FILTER_IN;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "i", 1) == 0)
 | |
| 		direct = FILTER_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = FILTER_OUT;
 | |
| 
 | |
| 	ret = peer_prefix_list_set(peer, afi, safi, direct, name_str);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_prefix_list_unset_vty(struct vty *vty, const char *ip_str,
 | |
| 				      afi_t afi, safi_t safi,
 | |
| 				      const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	int direct = FILTER_IN;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "i", 1) == 0)
 | |
| 		direct = FILTER_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = FILTER_OUT;
 | |
| 
 | |
| 	ret = peer_prefix_list_unset(peer, afi, safi, direct);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_prefix_list,
 | |
|        neighbor_prefix_list_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Filter updates to/from this neighbor\n"
 | |
|        "Name of a prefix list\n"
 | |
|        "Filter incoming updates\n"
 | |
|        "Filter outgoing updates\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int idx_in_out = 4;
 | |
| 	return peer_prefix_list_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_word]->arg, argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_prefix_list, neighbor_prefix_list_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Filter updates to/from this neighbor\n"
 | |
| 	     "Name of a prefix list\n"
 | |
| 	     "Filter incoming updates\n"
 | |
| 	     "Filter outgoing updates\n")
 | |
| 
 | |
| DEFUN (no_neighbor_prefix_list,
 | |
|        no_neighbor_prefix_list_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Filter updates to/from this neighbor\n"
 | |
|        "Name of a prefix list\n"
 | |
|        "Filter incoming updates\n"
 | |
|        "Filter outgoing updates\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int idx_in_out = 5;
 | |
| 	return peer_prefix_list_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 					  bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 					  argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_prefix_list, no_neighbor_prefix_list_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Filter updates to/from this neighbor\n"
 | |
| 	     "Name of a prefix list\n"
 | |
| 	     "Filter incoming updates\n"
 | |
| 	     "Filter outgoing updates\n")
 | |
| 
 | |
| static int peer_aslist_set_vty(struct vty *vty, const char *ip_str, afi_t afi,
 | |
| 			       safi_t safi, const char *name_str,
 | |
| 			       const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	int direct = FILTER_IN;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "i", 1) == 0)
 | |
| 		direct = FILTER_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = FILTER_OUT;
 | |
| 
 | |
| 	ret = peer_aslist_set(peer, afi, safi, direct, name_str);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_aslist_unset_vty(struct vty *vty, const char *ip_str, afi_t afi,
 | |
| 				 safi_t safi, const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	int direct = FILTER_IN;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "i", 1) == 0)
 | |
| 		direct = FILTER_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = FILTER_OUT;
 | |
| 
 | |
| 	ret = peer_aslist_unset(peer, afi, safi, direct);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_filter_list,
 | |
|        neighbor_filter_list_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Establish BGP filters\n"
 | |
|        "AS path access-list name\n"
 | |
|        "Filter incoming routes\n"
 | |
|        "Filter outgoing routes\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int idx_in_out = 4;
 | |
| 	return peer_aslist_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
 | |
| 				   bgp_node_safi(vty), argv[idx_word]->arg,
 | |
| 				   argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_filter_list, neighbor_filter_list_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Establish BGP filters\n"
 | |
| 	     "AS path access-list name\n"
 | |
| 	     "Filter incoming routes\n"
 | |
| 	     "Filter outgoing routes\n")
 | |
| 
 | |
| DEFUN (no_neighbor_filter_list,
 | |
|        no_neighbor_filter_list_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Establish BGP filters\n"
 | |
|        "AS path access-list name\n"
 | |
|        "Filter incoming routes\n"
 | |
|        "Filter outgoing routes\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int idx_in_out = 5;
 | |
| 	return peer_aslist_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 				     bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				     argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_filter_list, no_neighbor_filter_list_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Establish BGP filters\n"
 | |
| 	     "AS path access-list name\n"
 | |
| 	     "Filter incoming routes\n"
 | |
| 	     "Filter outgoing routes\n")
 | |
| 
 | |
| /* Set advertise-map to the peer. */
 | |
| static int peer_advertise_map_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				      afi_t afi, safi_t safi,
 | |
| 				      const char *advertise_str,
 | |
| 				      const char *condition_str, bool condition,
 | |
| 				      bool set)
 | |
| {
 | |
| 	int ret = CMD_WARNING_CONFIG_FAILED;
 | |
| 	struct peer *peer;
 | |
| 	struct route_map *advertise_map;
 | |
| 	struct route_map *condition_map;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return ret;
 | |
| 
 | |
| 	condition_map = route_map_lookup_warn_noexist(vty, condition_str);
 | |
| 	advertise_map = route_map_lookup_warn_noexist(vty, advertise_str);
 | |
| 
 | |
| 	if (set)
 | |
| 		ret = peer_advertise_map_set(peer, afi, safi, advertise_str,
 | |
| 					     advertise_map, condition_str,
 | |
| 					     condition_map, condition);
 | |
| 	else
 | |
| 		ret = peer_advertise_map_unset(peer, afi, safi, advertise_str,
 | |
| 					       advertise_map, condition_str,
 | |
| 					       condition_map, condition);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_condadv_period,
 | |
|        bgp_condadv_period_cmd,
 | |
|        "[no$no] bgp conditional-advertisement timer (5-240)$period",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Conditional advertisement settings\n"
 | |
|        "Set period to rescan BGP table to check if condition is met\n"
 | |
|        "Period between BGP table scans, in seconds; default 60\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->condition_check_period =
 | |
| 		no ? DEFAULT_CONDITIONAL_ROUTES_POLL_TIME : period;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_def_originate_eval,
 | |
|        bgp_def_originate_eval_cmd,
 | |
|        "[no$no] bgp default-originate timer (0-3600)$timer",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Control default-originate\n"
 | |
|        "Set period to rescan BGP table to check if default-originate condition is met\n"
 | |
|        "Period between BGP table scans, in seconds; default 5\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	bgp->rmap_def_originate_eval_timer =
 | |
| 		no ? RMAP_DEFAULT_ORIGINATE_EVAL_TIMER : timer;
 | |
| 
 | |
| 	if (bgp->t_rmap_def_originate_eval)
 | |
| 		EVENT_OFF(bgp->t_rmap_def_originate_eval);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (neighbor_advertise_map,
 | |
|        neighbor_advertise_map_cmd,
 | |
|        "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor advertise-map RMAP_NAME$advertise_str <exist-map|non-exist-map>$exist RMAP_NAME$condition_str",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Route-map to conditionally advertise routes\n"
 | |
|        "Name of advertise map\n"
 | |
|        "Advertise routes only if prefixes in exist-map are installed in BGP table\n"
 | |
|        "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n"
 | |
|        "Name of the exist or non exist map\n")
 | |
| {
 | |
| 	bool condition = CONDITION_EXIST;
 | |
| 
 | |
| 	if (!strcmp(exist, "non-exist-map"))
 | |
| 		condition = CONDITION_NON_EXIST;
 | |
| 
 | |
| 	return peer_advertise_map_set_vty(vty, neighbor, bgp_node_afi(vty),
 | |
| 					  bgp_node_safi(vty), advertise_str,
 | |
| 					  condition_str, condition, !no);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_advertise_map, neighbor_advertise_map_hidden_cmd,
 | |
| 	     "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor advertise-map RMAP_NAME$advertise_str <exist-map|non-exist-map>$exist RMAP_NAME$condition_str",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Route-map to conditionally advertise routes\n"
 | |
| 	     "Name of advertise map\n"
 | |
| 	     "Advertise routes only if prefixes in exist-map are installed in BGP table\n"
 | |
| 	     "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n"
 | |
| 	     "Name of the exist or non exist map\n")
 | |
| 
 | |
| /* Set route-map to the peer. */
 | |
| static int peer_route_map_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				  afi_t afi, safi_t safi, const char *name_str,
 | |
| 				  const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	int direct = RMAP_IN;
 | |
| 	struct route_map *route_map;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "in", 2) == 0)
 | |
| 		direct = RMAP_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = RMAP_OUT;
 | |
| 
 | |
| 	route_map = route_map_lookup_warn_noexist(vty, name_str);
 | |
| 	ret = peer_route_map_set(peer, afi, safi, direct, name_str, route_map);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_route_map_unset_vty(struct vty *vty, const char *ip_str,
 | |
| 				    afi_t afi, safi_t safi,
 | |
| 				    const char *direct_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	int direct = RMAP_IN;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/* Check filter direction. */
 | |
| 	if (strncmp(direct_str, "in", 2) == 0)
 | |
| 		direct = RMAP_IN;
 | |
| 	else if (strncmp(direct_str, "o", 1) == 0)
 | |
| 		direct = RMAP_OUT;
 | |
| 
 | |
| 	ret = peer_route_map_unset(peer, afi, safi, direct);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_route_map,
 | |
|        neighbor_route_map_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> route-map RMAP_NAME <in|out>",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Apply route map to neighbor\n"
 | |
|        "Name of route map\n"
 | |
|        "Apply map to incoming routes\n"
 | |
|        "Apply map to outbound routes\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int idx_in_out = 4;
 | |
| 	return peer_route_map_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_word]->arg, argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_route_map, neighbor_route_map_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> route-map RMAP_NAME <in|out>",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Apply route map to neighbor\n"
 | |
| 	     "Name of route map\n"
 | |
| 	     "Apply map to incoming routes\n"
 | |
| 	     "Apply map to outbound routes\n")
 | |
| 
 | |
| DEFUN (no_neighbor_route_map,
 | |
|        no_neighbor_route_map_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map RMAP_NAME <in|out>",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Apply route map to neighbor\n"
 | |
|        "Name of route map\n"
 | |
|        "Apply map to incoming routes\n"
 | |
|        "Apply map to outbound routes\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int idx_in_out = 5;
 | |
| 	return peer_route_map_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 					bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 					argv[idx_in_out]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_route_map, no_neighbor_route_map_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map RMAP_NAME <in|out>",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Apply route map to neighbor\n"
 | |
| 	     "Name of route map\n"
 | |
| 	     "Apply map to incoming routes\n"
 | |
| 	     "Apply map to outbound routes\n")
 | |
| 
 | |
| /* Set unsuppress-map to the peer. */
 | |
| static int peer_unsuppress_map_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				       afi_t afi, safi_t safi,
 | |
| 				       const char *name_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	struct route_map *route_map;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	route_map = route_map_lookup_warn_noexist(vty, name_str);
 | |
| 	ret = peer_unsuppress_map_set(peer, afi, safi, name_str, route_map);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| /* Unset route-map from the peer. */
 | |
| static int peer_unsuppress_map_unset_vty(struct vty *vty, const char *ip_str,
 | |
| 					 afi_t afi, safi_t safi)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_unsuppress_map_unset(peer, afi, safi);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_unsuppress_map,
 | |
|        neighbor_unsuppress_map_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Route-map to selectively unsuppress suppressed routes\n"
 | |
|        "Name of route map\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_word = 3;
 | |
| 	return peer_unsuppress_map_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_word]->arg);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_unsuppress_map, neighbor_unsuppress_map_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Route-map to selectively unsuppress suppressed routes\n"
 | |
| 	     "Name of route map\n")
 | |
| 
 | |
| DEFUN (no_neighbor_unsuppress_map,
 | |
|        no_neighbor_unsuppress_map_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Route-map to selectively unsuppress suppressed routes\n"
 | |
|        "Name of route map\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_unsuppress_map_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 					     bgp_node_afi(vty),
 | |
| 					     bgp_node_safi(vty));
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_unsuppress_map, no_neighbor_unsuppress_map_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Route-map to selectively unsuppress suppressed routes\n"
 | |
| 	     "Name of route map\n")
 | |
| 
 | |
| static int peer_maximum_prefix_set_vty(struct vty *vty, const char *ip_str,
 | |
| 				       afi_t afi, safi_t safi,
 | |
| 				       const char *num_str,
 | |
| 				       const char *threshold_str, int warning,
 | |
| 				       const char *restart_str,
 | |
| 				       const char *force_str)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 	uint32_t max;
 | |
| 	uint8_t threshold;
 | |
| 	uint16_t restart;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	max = strtoul(num_str, NULL, 10);
 | |
| 	if (threshold_str)
 | |
| 		threshold = atoi(threshold_str);
 | |
| 	else
 | |
| 		threshold = MAXIMUM_PREFIX_THRESHOLD_DEFAULT;
 | |
| 
 | |
| 	if (restart_str)
 | |
| 		restart = atoi(restart_str);
 | |
| 	else
 | |
| 		restart = 0;
 | |
| 
 | |
| 	ret = peer_maximum_prefix_set(peer, afi, safi, max, threshold, warning,
 | |
| 				      restart, force_str ? true : false);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| static int peer_maximum_prefix_unset_vty(struct vty *vty, const char *ip_str,
 | |
| 					 afi_t afi, safi_t safi)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, ip_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_maximum_prefix_unset(peer, afi, safi);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| /* Maximum number of prefix to be sent to the neighbor. */
 | |
| DEFUN(neighbor_maximum_prefix_out,
 | |
|       neighbor_maximum_prefix_out_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out (1-4294967295)",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Maximum number of prefixes to be sent to this peer\n"
 | |
|       "Maximum no. of prefix limit\n")
 | |
| {
 | |
| 	int ret;
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	struct peer *peer;
 | |
| 	uint32_t max;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	max = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	ret = peer_maximum_prefix_out_set(peer, afi, safi, max);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_maximum_prefix_out,
 | |
|       no_neighbor_maximum_prefix_out_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out [(1-4294967295)]",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Maximum number of prefixes to be sent to this peer\n"
 | |
|       "Maximum no. of prefix limit\n")
 | |
| {
 | |
| 	int ret;
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_maximum_prefix_out_unset(peer, afi, safi);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| /* Maximum number of prefix configuration. Prefix count is different
 | |
|    for each peer configuration. So this configuration can be set for
 | |
|    each peer configuration. */
 | |
| DEFUN (neighbor_maximum_prefix,
 | |
|        neighbor_maximum_prefix_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefix accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, NULL, 0, NULL, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_maximum_prefix, neighbor_maximum_prefix_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) [force]",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Maximum number of prefix accept from this peer\n"
 | |
| 	     "maximum no. of prefix limit\n"
 | |
| 	     "Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (neighbor_maximum_prefix_threshold,
 | |
|        neighbor_maximum_prefix_threshold_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefix accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Threshold value (%) at which to generate a warning msg\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_number_2 = 4;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, argv[idx_number_2]->arg, 0, NULL, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_maximum_prefix_threshold,
 | |
| 	neighbor_maximum_prefix_threshold_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) [force]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefix accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Threshold value (%) at which to generate a warning msg\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (neighbor_maximum_prefix_warning,
 | |
|        neighbor_maximum_prefix_warning_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) warning-only [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefix accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Only give warning message when limit is exceeded\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, NULL, 1, NULL, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_maximum_prefix_warning,
 | |
| 	neighbor_maximum_prefix_warning_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) warning-only [force]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefix accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Only give warning message when limit is exceeded\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (neighbor_maximum_prefix_threshold_warning,
 | |
|        neighbor_maximum_prefix_threshold_warning_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) warning-only [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefix accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Threshold value (%) at which to generate a warning msg\n"
 | |
|        "Only give warning message when limit is exceeded\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_number_2 = 4;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, argv[idx_number_2]->arg, 1, NULL, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_maximum_prefix_threshold_warning,
 | |
| 	neighbor_maximum_prefix_threshold_warning_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) warning-only [force]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefix accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Threshold value (%) at which to generate a warning msg\n"
 | |
| 	"Only give warning message when limit is exceeded\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (neighbor_maximum_prefix_restart,
 | |
|        neighbor_maximum_prefix_restart_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) restart (1-65535) [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefix accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Restart bgp connection after limit is exceeded\n"
 | |
|        "Restart interval in minutes\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_number_2 = 5;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, NULL, 0, argv[idx_number_2]->arg, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_maximum_prefix_restart,
 | |
| 	neighbor_maximum_prefix_restart_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) restart (1-65535) [force]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefix accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Restart bgp connection after limit is exceeded\n"
 | |
| 	"Restart interval in minutes\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (neighbor_maximum_prefix_threshold_restart,
 | |
|        neighbor_maximum_prefix_threshold_restart_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) restart (1-65535) [force]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefixes to accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Threshold value (%) at which to generate a warning msg\n"
 | |
|        "Restart bgp connection after limit is exceeded\n"
 | |
|        "Restart interval in minutes\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_number_2 = 4;
 | |
| 	int idx_number_3 = 6;
 | |
| 	int idx_force = 0;
 | |
| 	char *force = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "force", &idx_force))
 | |
| 		force = argv[idx_force]->arg;
 | |
| 
 | |
| 	return peer_maximum_prefix_set_vty(
 | |
| 		vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 		argv[idx_number]->arg, argv[idx_number_2]->arg, 0,
 | |
| 		argv[idx_number_3]->arg, force);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_maximum_prefix_threshold_restart,
 | |
| 	neighbor_maximum_prefix_threshold_restart_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) restart (1-65535) [force]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefixes to accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Threshold value (%) at which to generate a warning msg\n"
 | |
| 	"Restart bgp connection after limit is exceeded\n"
 | |
| 	"Restart interval in minutes\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| DEFUN (no_neighbor_maximum_prefix,
 | |
|        no_neighbor_maximum_prefix_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix [(1-4294967295) [(1-100)] [restart (1-65535)] [warning-only] [force]]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Maximum number of prefixes to accept from this peer\n"
 | |
|        "maximum no. of prefix limit\n"
 | |
|        "Threshold value (%) at which to generate a warning msg\n"
 | |
|        "Restart bgp connection after limit is exceeded\n"
 | |
|        "Restart interval in minutes\n"
 | |
|        "Only give warning message when limit is exceeded\n"
 | |
|        "Force checking all received routes not only accepted\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	return peer_maximum_prefix_unset_vty(vty, argv[idx_peer]->arg,
 | |
| 					     bgp_node_afi(vty),
 | |
| 					     bgp_node_safi(vty));
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix [(1-4294967295) [(1-100)] [restart (1-65535)] [warning-only] [force]]",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Maximum number of prefixes to accept from this peer\n"
 | |
| 	"maximum no. of prefix limit\n"
 | |
| 	"Threshold value (%) at which to generate a warning msg\n"
 | |
| 	"Restart bgp connection after limit is exceeded\n"
 | |
| 	"Restart interval in minutes\n"
 | |
| 	"Only give warning message when limit is exceeded\n"
 | |
| 	"Force checking all received routes not only accepted\n")
 | |
| 
 | |
| /* "neighbor accept-own" */
 | |
| DEFPY (neighbor_accept_own,
 | |
|        neighbor_accept_own_cmd,
 | |
|        "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor accept-own",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Enable handling of self-originated VPN routes containing ACCEPT_OWN community\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 	int ret;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (no)
 | |
| 		ret = peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
 | |
| 	else
 | |
| 		ret = peer_af_flag_set(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| /* "neighbor soo" */
 | |
| DEFPY (neighbor_soo,
 | |
|        neighbor_soo_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor soo ASN:NN_OR_IP-ADDRESS:NN$soo",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set the Site-of-Origin (SoO) extended community\n"
 | |
|        "VPN extended community\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 	struct ecommunity *ecomm_soo;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ecomm_soo = ecommunity_str2com(soo, ECOMMUNITY_SITE_ORIGIN, 0);
 | |
| 	if (!ecomm_soo) {
 | |
| 		vty_out(vty, "%% Malformed SoO extended community\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 	ecommunity_str(ecomm_soo);
 | |
| 
 | |
| 	if (!ecommunity_match(peer->soo[afi][safi], ecomm_soo)) {
 | |
| 		ecommunity_free(&peer->soo[afi][safi]);
 | |
| 		peer->soo[afi][safi] = ecomm_soo;
 | |
| 		peer_af_flag_unset(peer, afi, safi, PEER_FLAG_SOO);
 | |
| 	}
 | |
| 
 | |
| 	return bgp_vty_return(vty,
 | |
| 			      peer_af_flag_set(peer, afi, safi, PEER_FLAG_SOO));
 | |
| }
 | |
| 
 | |
| DEFPY (no_neighbor_soo,
 | |
|        no_neighbor_soo_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor soo [ASN:NN_OR_IP-ADDRESS:NN$soo]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Set the Site-of-Origin (SoO) extended community\n"
 | |
|        "VPN extended community\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ecommunity_free(&peer->soo[afi][safi]);
 | |
| 
 | |
| 	return bgp_vty_return(
 | |
| 		vty, peer_af_flag_unset(peer, afi, safi, PEER_FLAG_SOO));
 | |
| }
 | |
| 
 | |
| /* "neighbor allowas-in" */
 | |
| DEFUN (neighbor_allowas_in,
 | |
|        neighbor_allowas_in_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Accept as-path with my AS present in it\n"
 | |
|        "Number of occurrences of AS number\n"
 | |
|        "Only accept my AS in the as-path if the route was originated in my AS\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number_origin = 3;
 | |
| 	int ret;
 | |
| 	int origin = 0;
 | |
| 	struct peer *peer;
 | |
| 	int allow_num = 0;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (argc <= idx_number_origin)
 | |
| 		allow_num = 3;
 | |
| 	else {
 | |
| 		if (argv[idx_number_origin]->type == WORD_TKN)
 | |
| 			origin = 1;
 | |
| 		else
 | |
| 			allow_num = atoi(argv[idx_number_origin]->arg);
 | |
| 	}
 | |
| 
 | |
| 	ret = peer_allowas_in_set(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  allow_num, origin);
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	neighbor_allowas_in, neighbor_allowas_in_hidden_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
 | |
| 	NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"Accept as-path with my AS present in it\n"
 | |
| 	"Number of occurrences of AS number\n"
 | |
| 	"Only accept my AS in the as-path if the route was originated in my AS\n")
 | |
| 
 | |
| DEFUN (no_neighbor_allowas_in,
 | |
|        no_neighbor_allowas_in_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "allow local ASN appears in aspath attribute\n"
 | |
|        "Number of occurrences of AS number\n"
 | |
|        "Only accept my AS in the as-path if the route was originated in my AS\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	int ret;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = peer_allowas_in_unset(peer, bgp_node_afi(vty),
 | |
| 				    bgp_node_safi(vty));
 | |
| 
 | |
| 	return bgp_vty_return(vty, ret);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_neighbor_allowas_in, no_neighbor_allowas_in_hidden_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
 | |
| 	NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	"allow local ASN appears in aspath attribute\n"
 | |
| 	"Number of occurrences of AS number\n"
 | |
| 	"Only accept my AS in the as-path if the route was originated in my AS\n")
 | |
| 
 | |
| DEFUN (neighbor_ttl_security,
 | |
|        neighbor_ttl_security_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> ttl-security hops (1-254)",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP ttl-security parameters\n"
 | |
|        "Specify the maximum number of hops to the BGP peer\n"
 | |
|        "Number of hops to BGP peer\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	int idx_number = 4;
 | |
| 	struct peer *peer;
 | |
| 	int gtsm_hops;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	gtsm_hops = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	/*
 | |
| 	 * If 'neighbor swpX', then this is for directly connected peers,
 | |
| 	 * we should not accept a ttl-security hops value greater than 1.
 | |
| 	 */
 | |
| 	if (peer->conf_if && (gtsm_hops > BGP_GTSM_HOPS_CONNECTED)) {
 | |
| 		vty_out(vty,
 | |
| 			"%s is directly connected peer, hops cannot exceed 1\n",
 | |
| 			argv[idx_peer]->arg);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return bgp_vty_return(vty, peer_ttl_security_hops_set(peer, gtsm_hops));
 | |
| }
 | |
| 
 | |
| DEFUN (no_neighbor_ttl_security,
 | |
|        no_neighbor_ttl_security_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> ttl-security hops (1-254)",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "BGP ttl-security parameters\n"
 | |
|        "Specify the maximum number of hops to the BGP peer\n"
 | |
|        "Number of hops to BGP peer\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return bgp_vty_return(vty, peer_ttl_security_hops_unset(peer));
 | |
| }
 | |
| 
 | |
| /* disable-addpath-rx */
 | |
| DEFUN(neighbor_disable_addpath_rx,
 | |
|       neighbor_disable_addpath_rx_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Do not accept additional paths\n")
 | |
| {
 | |
| 	char *peer_str = argv[1]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return peer_af_flag_set_vty(vty, peer_str, afi, safi,
 | |
| 				    PEER_FLAG_DISABLE_ADDPATH_RX);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_disable_addpath_rx,
 | |
|       no_neighbor_disable_addpath_rx_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Do not accept additional paths\n")
 | |
| {
 | |
| 	char *peer_str = argv[2]->arg;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi = bgp_node_afi(vty);
 | |
| 	safi_t safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
 | |
| 				      PEER_FLAG_DISABLE_ADDPATH_RX);
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_addpath_tx_all_paths,
 | |
|        neighbor_addpath_tx_all_paths_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise all paths to a neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_ALL, 0);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_addpath_tx_all_paths,
 | |
| 	     neighbor_addpath_tx_all_paths_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Use addpath to advertise all paths to a neighbor\n")
 | |
| 
 | |
| DEFUN (no_neighbor_addpath_tx_all_paths,
 | |
|        no_neighbor_addpath_tx_all_paths_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise all paths to a neighbor\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (peer->addpath_type[bgp_node_afi(vty)][bgp_node_safi(vty)]
 | |
| 	    != BGP_ADDPATH_ALL) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Peer not currently configured to transmit all paths.");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_NONE, 0);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_addpath_tx_all_paths,
 | |
| 	     no_neighbor_addpath_tx_all_paths_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Use addpath to advertise all paths to a neighbor\n")
 | |
| 
 | |
| DEFPY (neighbor_addpath_tx_best_selected_paths,
 | |
|        neighbor_addpath_tx_best_selected_paths_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-tx-best-selected (1-6)$paths",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise best selected paths to a neighbor\n"
 | |
|        "The number of best paths\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_BEST_SELECTED, paths);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_neighbor_addpath_tx_best_selected_paths,
 | |
|        no_neighbor_addpath_tx_best_selected_paths_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-tx-best-selected [(1-6)]",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise best selected paths to a neighbor\n"
 | |
|        "The number of best paths\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_BEST_SELECTED, 0);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (neighbor_addpath_tx_bestpath_per_as,
 | |
|        neighbor_addpath_tx_bestpath_per_as_cmd,
 | |
|        "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise the bestpath per each neighboring AS\n")
 | |
| {
 | |
| 	int idx_peer = 1;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_BEST_PER_AS, 0);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(neighbor_addpath_tx_bestpath_per_as,
 | |
| 	     neighbor_addpath_tx_bestpath_per_as_hidden_cmd,
 | |
| 	     "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
 | |
| 	     NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Use addpath to advertise the bestpath per each neighboring AS\n")
 | |
| 
 | |
| DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
 | |
|        no_neighbor_addpath_tx_bestpath_per_as_cmd,
 | |
|        "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
 | |
|        NO_STR
 | |
|        NEIGHBOR_STR
 | |
|        NEIGHBOR_ADDR_STR2
 | |
|        "Use addpath to advertise the bestpath per each neighboring AS\n")
 | |
| {
 | |
| 	int idx_peer = 2;
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (peer->addpath_type[bgp_node_afi(vty)][bgp_node_safi(vty)]
 | |
| 	    != BGP_ADDPATH_BEST_PER_AS) {
 | |
| 		vty_out(vty,
 | |
| 			"%% Peer not currently configured to transmit all best path per as.");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 				  BGP_ADDPATH_NONE, 0);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(no_neighbor_addpath_tx_bestpath_per_as,
 | |
| 	     no_neighbor_addpath_tx_bestpath_per_as_hidden_cmd,
 | |
| 	     "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
 | |
| 	     NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
| 	     "Use addpath to advertise the bestpath per each neighboring AS\n")
 | |
| 
 | |
| DEFPY(
 | |
| 	neighbor_aspath_loop_detection, neighbor_aspath_loop_detection_cmd,
 | |
| 	"neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor sender-as-path-loop-detection",
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	"Detect AS loops before sending to neighbor\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	peer->as_path_loop_detection = true;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(
 | |
| 	no_neighbor_aspath_loop_detection,
 | |
| 	no_neighbor_aspath_loop_detection_cmd,
 | |
| 	"no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor sender-as-path-loop-detection",
 | |
| 	NO_STR
 | |
| 	NEIGHBOR_STR
 | |
| 	NEIGHBOR_ADDR_STR2
 | |
| 	"Detect AS loops before sending to neighbor\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	peer->as_path_loop_detection = false;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(neighbor_path_attribute_discard,
 | |
|       neighbor_path_attribute_discard_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute discard (1-255)...",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Manipulate path attributes from incoming UPDATE messages\n"
 | |
|       "Drop specified attributes from incoming UPDATE messages\n"
 | |
|       "Attribute number\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	int idx = 0;
 | |
| 	char *discard_attrs = NULL;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	argv_find(argv, argc, "(1-255)", &idx);
 | |
| 	if (idx)
 | |
| 		discard_attrs = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	bgp_path_attribute_discard_vty(vty, peer, discard_attrs, true);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, discard_attrs);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(no_neighbor_path_attribute_discard,
 | |
|       no_neighbor_path_attribute_discard_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute discard [(1-255)]",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Manipulate path attributes from incoming UPDATE messages\n"
 | |
|       "Drop specified attributes from incoming UPDATE messages\n"
 | |
|       "Attribute number\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	int idx = 0;
 | |
| 	char *discard_attrs = NULL;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	argv_find(argv, argc, "(1-255)", &idx);
 | |
| 	if (idx)
 | |
| 		discard_attrs = argv[idx]->arg;
 | |
| 
 | |
| 	bgp_path_attribute_discard_vty(vty, peer, discard_attrs, false);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, discard_attrs);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(neighbor_path_attribute_treat_as_withdraw,
 | |
|       neighbor_path_attribute_treat_as_withdraw_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Manipulate path attributes from incoming UPDATE messages\n"
 | |
|       "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
 | |
|       "Attribute number\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	int idx = 0;
 | |
| 	char *withdraw_attrs = NULL;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	argv_find(argv, argc, "(1-255)", &idx);
 | |
| 	if (idx)
 | |
| 		withdraw_attrs = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, true);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, withdraw_attrs);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
 | |
|       no_neighbor_path_attribute_treat_as_withdraw_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
 | |
|       NO_STR
 | |
|       NEIGHBOR_STR
 | |
|       NEIGHBOR_ADDR_STR2
 | |
|       "Manipulate path attributes from incoming UPDATE messages\n"
 | |
|       "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
 | |
|       "Attribute number\n")
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	int idx = 0;
 | |
| 	char *withdraw_attrs = NULL;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, neighbor);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	argv_find(argv, argc, "(1-255)", &idx);
 | |
| 	if (idx)
 | |
| 		withdraw_attrs = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, false);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, withdraw_attrs);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
 | |
| 			 struct ecommunity **list, bool is_rt6)
 | |
| {
 | |
| 	struct ecommunity *ecom = NULL;
 | |
| 	struct ecommunity *ecomadd;
 | |
| 
 | |
| 	for (; argc; --argc, ++argv) {
 | |
| 		if (is_rt6)
 | |
| 			ecomadd = ecommunity_str2com_ipv6(argv[0]->arg,
 | |
| 						ECOMMUNITY_ROUTE_TARGET,
 | |
| 						0);
 | |
| 		else
 | |
| 			ecomadd = ecommunity_str2com(argv[0]->arg,
 | |
| 						ECOMMUNITY_ROUTE_TARGET,
 | |
| 						0);
 | |
| 		if (!ecomadd) {
 | |
| 			vty_out(vty, "Malformed community-list value\n");
 | |
| 			if (ecom)
 | |
| 				ecommunity_free(&ecom);
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 
 | |
| 		if (ecom) {
 | |
| 			ecommunity_merge(ecom, ecomadd);
 | |
| 			ecommunity_free(&ecomadd);
 | |
| 		} else {
 | |
| 			ecom = ecomadd;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (*list) {
 | |
| 		ecommunity_free(&*list);
 | |
| 	}
 | |
| 	*list = ecom;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * v2vimport is true if we are handling a `import vrf ...` command
 | |
|  */
 | |
| static afi_t vpn_policy_getafi(struct vty *vty, struct bgp *bgp, bool v2vimport)
 | |
| {
 | |
| 	afi_t afi;
 | |
| 
 | |
| 	switch (vty->node) {
 | |
| 	case BGP_IPV4_NODE:
 | |
| 		afi = AFI_IP;
 | |
| 		break;
 | |
| 	case BGP_IPV6_NODE:
 | |
| 		afi = AFI_IP6;
 | |
| 		break;
 | |
| 	default:
 | |
| 		vty_out(vty,
 | |
| 			"%% context error: valid only in address-family <ipv4|ipv6> unicast block\n");
 | |
| 		return AFI_MAX;
 | |
| 	}
 | |
| 
 | |
| 	if (!v2vimport) {
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 			       BGP_CONFIG_VRF_TO_VRF_IMPORT)
 | |
| 		    || CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 				  BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% error: Please unconfigure import vrf commands before using vpn commands\n");
 | |
| 			return AFI_MAX;
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 			       BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
 | |
| 		    || CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 				  BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% error: Please unconfigure vpn to vrf commands before using import vrf commands\n");
 | |
| 			return AFI_MAX;
 | |
| 		}
 | |
| 	}
 | |
| 	return afi;
 | |
| }
 | |
| 
 | |
| DEFPY (af_rd_vpn_export,
 | |
|        af_rd_vpn_export_cmd,
 | |
|        "[no] rd vpn export ASN:NN_OR_IP-ADDRESS:NN$rd_str",
 | |
|        NO_STR
 | |
|        "Specify route distinguisher\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "Route Distinguisher (<as-number>:<number> | <ip-address>:<number>)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct prefix_rd prd;
 | |
| 	int ret;
 | |
| 	afi_t afi;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	if (yes) {
 | |
| 		ret = str2prefix_rd(rd_str, &prd);
 | |
| 		if (!ret) {
 | |
| 			vty_out(vty, "%% Malformed rd\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/*
 | |
| 	 * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
 | |
| 	 */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			   bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (yes) {
 | |
| 		bgp->vpn_policy[afi].tovpn_rd_pretty =
 | |
| 			XSTRDUP(MTYPE_BGP, rd_str);
 | |
| 		bgp->vpn_policy[afi].tovpn_rd = prd;
 | |
| 		SET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			 BGP_VPN_POLICY_TOVPN_RD_SET);
 | |
| 	} else {
 | |
| 		XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
 | |
| 		UNSET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			   BGP_VPN_POLICY_TOVPN_RD_SET);
 | |
| 	}
 | |
| 
 | |
| 	/* post-change: re-export vpn routes */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			    bgp_get_default(), bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS (af_rd_vpn_export,
 | |
|        af_no_rd_vpn_export_cmd,
 | |
|        "no rd vpn export",
 | |
|        NO_STR
 | |
|        "Specify route distinguisher\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n")
 | |
| 
 | |
| DEFPY(af_label_vpn_export_allocation_mode,
 | |
|       af_label_vpn_export_allocation_mode_cmd,
 | |
|       "[no$no] label vpn export allocation-mode <per-vrf$label_per_vrf|per-nexthop$label_per_nh>",
 | |
|       NO_STR
 | |
|       "label value for VRF\n"
 | |
|       "Between current address-family and vpn\n"
 | |
|       "For routes leaked from current address-family to vpn\n"
 | |
|       "Label allocation mode\n"
 | |
|       "Allocate one label for all BGP updates of the VRF\n"
 | |
|       "Allocate a label per connected next-hop in the VRF\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	afi_t afi;
 | |
| 	bool old_per_nexthop, new_per_nexthop;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	old_per_nexthop = !!CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 				       BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP);
 | |
| 	if (no) {
 | |
| 		if (old_per_nexthop == false && label_per_nh)
 | |
| 			return CMD_ERR_NO_MATCH;
 | |
| 		if (old_per_nexthop == true && label_per_vrf)
 | |
| 			return CMD_ERR_NO_MATCH;
 | |
| 		new_per_nexthop = false;
 | |
| 	} else {
 | |
| 		if (label_per_nh)
 | |
| 			new_per_nexthop = true;
 | |
| 		else
 | |
| 			new_per_nexthop = false;
 | |
| 	}
 | |
| 
 | |
| 	/* no change */
 | |
| 	if (old_per_nexthop == new_per_nexthop)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/*
 | |
| 	 * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
 | |
| 	 */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(),
 | |
| 			   bgp);
 | |
| 
 | |
| 	if (new_per_nexthop)
 | |
| 		SET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			 BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP);
 | |
| 	else
 | |
| 		UNSET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			   BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP);
 | |
| 
 | |
| 	/* post-change: re-export vpn routes */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(),
 | |
| 			    bgp);
 | |
| 
 | |
| 	hook_call(bgp_snmp_update_last_changed, bgp);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (af_label_vpn_export,
 | |
|        af_label_vpn_export_cmd,
 | |
|        "[no] label vpn export <(0-1048575)$label_val|auto$label_auto>",
 | |
|        NO_STR
 | |
|        "label value for VRF\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "Label Value <0-1048575>\n"
 | |
|        "Automatically assign a label\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	mpls_label_t label = MPLS_LABEL_NONE;
 | |
| 	afi_t afi;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	/* If "no ...", squash trailing parameter */
 | |
| 	if (!yes)
 | |
| 		label_auto = NULL;
 | |
| 
 | |
| 	if (yes) {
 | |
| 		if (!label_auto)
 | |
| 			label = label_val; /* parser should force unsigned */
 | |
| 	}
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 
 | |
| 	if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 				     BGP_VPN_POLICY_TOVPN_LABEL_AUTO))
 | |
| 		/* no change */
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/*
 | |
| 	 * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
 | |
| 	 */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			   bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (!label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 				      BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
 | |
| 
 | |
| 		if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
 | |
| 
 | |
| 			/*
 | |
| 			 * label has previously been automatically
 | |
| 			 * assigned by labelpool: release it
 | |
| 			 *
 | |
| 			 * NB if tovpn_label == MPLS_LABEL_NONE it
 | |
| 			 * means the automatic assignment is in flight
 | |
| 			 * and therefore the labelpool callback must
 | |
| 			 * detect that the auto label is not needed.
 | |
| 			 */
 | |
| 
 | |
| 			bgp_lp_release(LP_TYPE_VRF,
 | |
| 				       &bgp->vpn_policy[afi],
 | |
| 				       bgp->vpn_policy[afi].tovpn_label);
 | |
| 		}
 | |
| 		UNSET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			   BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
 | |
| 	}
 | |
| 
 | |
| 	bgp->vpn_policy[afi].tovpn_label = label;
 | |
| 	if (label_auto) {
 | |
| 		SET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			 BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
 | |
| 		bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi],
 | |
| 			   vpn_leak_label_callback);
 | |
| 	}
 | |
| 
 | |
| 	/* post-change: re-export vpn routes */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			    bgp_get_default(), bgp);
 | |
| 
 | |
| 	hook_call(bgp_snmp_update_last_changed, bgp);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (af_sid_vpn_export,
 | |
|        af_sid_vpn_export_cmd,
 | |
|        "[no] sid vpn export <(1-1048575)$sid_idx|auto$sid_auto>",
 | |
|        NO_STR
 | |
|        "sid value for VRF\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "Sid allocation index\n"
 | |
|        "Automatically assign a label\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	afi_t afi;
 | |
| 	int debug = 0;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 	debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
 | |
| 		 BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (!yes) {
 | |
| 		/* when SID is not set, do nothing */
 | |
| 		if ((bgp->vpn_policy[afi].tovpn_sid_index == 0) &&
 | |
| 		    !CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 				BGP_VPN_POLICY_TOVPN_SID_AUTO))
 | |
| 			return CMD_SUCCESS;
 | |
| 
 | |
| 		/* pre-change */
 | |
| 		vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 				   bgp_get_default(), bgp);
 | |
| 		bgp->vpn_policy[afi].tovpn_sid_index = 0;
 | |
| 		UNSET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			   BGP_VPN_POLICY_TOVPN_SID_AUTO);
 | |
| 
 | |
| 		/* post-change */
 | |
| 		vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 				    bgp_get_default(), bgp);
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	if (bgp->tovpn_sid_index != 0 ||
 | |
| 	    CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)) {
 | |
| 		vty_out(vty,
 | |
| 			"per-vrf sid and per-af sid are mutually exclusive\n"
 | |
| 			"Failed: per-vrf sid is configured. Remove per-vrf sid before configuring per-af sid\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	/* skip when it's already configured */
 | |
| 	if ((sid_idx != 0 && bgp->vpn_policy[afi].tovpn_sid_index != 0)
 | |
| 	    || (sid_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 				       BGP_VPN_POLICY_TOVPN_SID_AUTO)))
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/*
 | |
| 	 * mode change between sid_idx and sid_auto isn't supported.
 | |
| 	 * user must negate sid vpn export when they want to change the mode
 | |
| 	 */
 | |
| 	if ((sid_auto && bgp->vpn_policy[afi].tovpn_sid_index != 0)
 | |
| 	    || (sid_idx != 0 && CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 					   BGP_VPN_POLICY_TOVPN_SID_AUTO))) {
 | |
| 		vty_out(vty, "it's already configured as %s.\n",
 | |
| 			sid_auto ? "auto-mode" : "idx-mode");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	/* pre-change */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			   bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (sid_auto) {
 | |
| 		/* SID allocation auto-mode */
 | |
| 		if (debug)
 | |
| 			zlog_debug("%s: auto sid alloc.", __func__);
 | |
| 		SET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			 BGP_VPN_POLICY_TOVPN_SID_AUTO);
 | |
| 	} else if (sid_idx != 0) {
 | |
| 		/* SID allocation index-mode */
 | |
| 		if (debug)
 | |
| 			zlog_debug("%s: idx %ld sid alloc.", __func__, sid_idx);
 | |
| 		bgp->vpn_policy[afi].tovpn_sid_index = sid_idx;
 | |
| 	}
 | |
| 
 | |
| 	/* post-change */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			    bgp_get_default(), bgp);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_sid_vpn_export,
 | |
|        bgp_sid_vpn_export_cmd,
 | |
|        "[no] sid vpn per-vrf export <(1-1048575)$sid_idx|auto$sid_auto>",
 | |
|        NO_STR
 | |
|        "sid value for VRF\n"
 | |
|        "Between current vrf and vpn\n"
 | |
|        "sid per-VRF (both IPv4 and IPv6 address families)\n"
 | |
|        "For routes leaked from current vrf to vpn\n"
 | |
|        "Sid allocation index\n"
 | |
|        "Automatically assign a label\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int debug;
 | |
| 
 | |
| 	debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
 | |
| 		 BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
 | |
| 
 | |
| 	if (no) {
 | |
| 		/* when per-VRF SID is not set, do nothing */
 | |
| 		if (bgp->tovpn_sid_index == 0 &&
 | |
| 		    !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
 | |
| 			return CMD_SUCCESS;
 | |
| 
 | |
| 		sid_idx = 0;
 | |
| 		sid_auto = false;
 | |
| 		bgp->tovpn_sid_index = 0;
 | |
| 		UNSET_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
 | |
| 	}
 | |
| 
 | |
| 	if (bgp->vpn_policy[AFI_IP].tovpn_sid_index != 0 ||
 | |
| 	    CHECK_FLAG(bgp->vpn_policy[AFI_IP].flags,
 | |
| 		       BGP_VPN_POLICY_TOVPN_SID_AUTO) ||
 | |
| 	    bgp->vpn_policy[AFI_IP6].tovpn_sid_index != 0 ||
 | |
| 	    CHECK_FLAG(bgp->vpn_policy[AFI_IP6].flags,
 | |
| 		       BGP_VPN_POLICY_TOVPN_SID_AUTO)) {
 | |
| 		vty_out(vty,
 | |
| 			"per-vrf sid and per-af sid are mutually exclusive\n"
 | |
| 			"Failed: per-af sid is configured. Remove per-af sid before configuring per-vrf sid\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	/* skip when it's already configured */
 | |
| 	if ((sid_idx != 0 && bgp->tovpn_sid_index != 0) ||
 | |
| 	    (sid_auto && CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)))
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/*
 | |
| 	 * mode change between sid_idx and sid_auto isn't supported.
 | |
| 	 * user must negate sid vpn export when they want to change the mode
 | |
| 	 */
 | |
| 	if ((sid_auto && bgp->tovpn_sid_index != 0) ||
 | |
| 	    (sid_idx != 0 &&
 | |
| 	     CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))) {
 | |
| 		vty_out(vty, "it's already configured as %s.\n",
 | |
| 			sid_auto ? "auto-mode" : "idx-mode");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	/* pre-change */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
 | |
| 			   bgp);
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp_get_default(),
 | |
| 			   bgp);
 | |
| 
 | |
| 	if (sid_auto) {
 | |
| 		/* SID allocation auto-mode */
 | |
| 		if (debug)
 | |
| 			zlog_debug("%s: auto per-vrf sid alloc.", __func__);
 | |
| 		SET_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
 | |
| 	} else if (sid_idx != 0) {
 | |
| 		/* SID allocation index-mode */
 | |
| 		if (debug)
 | |
| 			zlog_debug("%s: idx %ld per-vrf sid alloc.", __func__,
 | |
| 				   sid_idx);
 | |
| 		bgp->tovpn_sid_index = sid_idx;
 | |
| 	}
 | |
| 
 | |
| 	/* post-change */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
 | |
| 			    bgp);
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6,
 | |
| 			    bgp_get_default(), bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS (af_label_vpn_export,
 | |
|        af_no_label_vpn_export_cmd,
 | |
|        "no label vpn export",
 | |
|        NO_STR
 | |
|        "label value for VRF\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n")
 | |
| 
 | |
| ALIAS (bgp_sid_vpn_export,
 | |
|        no_bgp_sid_vpn_export_cmd,
 | |
|        "no$no sid vpn per-vrf export",
 | |
|        NO_STR
 | |
|        "sid value for VRF\n"
 | |
|        "Between current vrf and vpn\n"
 | |
|        "sid per-VRF (both IPv4 and IPv6 address families)\n"
 | |
|        "For routes leaked from current vrf to vpn\n")
 | |
| 
 | |
| DEFPY (af_nexthop_vpn_export,
 | |
|        af_nexthop_vpn_export_cmd,
 | |
|        "[no] nexthop vpn export [<A.B.C.D|X:X::X:X>$nexthop_su]",
 | |
|        NO_STR
 | |
|        "Specify next hop to use for VRF advertised prefixes\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "IPv4 prefix\n"
 | |
|        "IPv6 prefix\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	afi_t afi;
 | |
| 	struct prefix p;
 | |
| 
 | |
| 	if (!no) {
 | |
| 		if (!nexthop_su) {
 | |
| 			vty_out(vty, "%% Nexthop required\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		if (!sockunion2hostprefix(nexthop_su, &p))
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	/*
 | |
| 	 * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
 | |
| 	 */
 | |
| 	vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			   bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (!no) {
 | |
| 		bgp->vpn_policy[afi].tovpn_nexthop = p;
 | |
| 		SET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			 BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
 | |
| 	} else {
 | |
| 		UNSET_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 			   BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
 | |
| 	}
 | |
| 
 | |
| 	/* post-change: re-export vpn routes */
 | |
| 	vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
 | |
| 			    bgp_get_default(), bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int vpn_policy_getdirs(struct vty *vty, const char *dstr, int *dodir)
 | |
| {
 | |
| 	if (!strcmp(dstr, "import")) {
 | |
| 		dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
 | |
| 	} else if (!strcmp(dstr, "export")) {
 | |
| 		dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
 | |
| 	} else if (!strcmp(dstr, "both")) {
 | |
| 		dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
 | |
| 		dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
 | |
| 	} else {
 | |
| 		vty_out(vty, "%% direction parse error\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (af_rt_vpn_imexport,
 | |
|        af_rt_vpn_imexport_cmd,
 | |
|        "[no] <rt|route-target> vpn <import|export|both>$direction_str RTLIST...",
 | |
|        NO_STR
 | |
|        "Specify route target list\n"
 | |
|        "Specify route target list\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from vpn to current address-family: match any\n"
 | |
|        "For routes leaked from current address-family to vpn: set\n"
 | |
|        "both import: match any and export: set\n"
 | |
|        "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 	struct ecommunity *ecom = NULL;
 | |
| 	int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
 | |
| 	enum vpn_policy_direction dir;
 | |
| 	afi_t afi;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = vpn_policy_getdirs(vty, direction_str, dodir);
 | |
| 	if (ret != CMD_SUCCESS)
 | |
| 		return ret;
 | |
| 
 | |
| 	if (yes) {
 | |
| 		if (!argv_find(argv, argc, "RTLIST", &idx)) {
 | |
| 			vty_out(vty, "%% Missing RTLIST\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		ret = set_ecom_list(vty, argc - idx, argv + idx, &ecom, false);
 | |
| 		if (ret != CMD_SUCCESS) {
 | |
| 			return ret;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
 | |
| 		if (!dodir[dir])
 | |
| 			continue;
 | |
| 
 | |
| 		vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 		if (yes) {
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir])
 | |
| 				ecommunity_free(
 | |
| 						&bgp->vpn_policy[afi].rtlist[dir]);
 | |
| 			bgp->vpn_policy[afi].rtlist[dir] =
 | |
| 				ecommunity_dup(ecom);
 | |
| 		} else {
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir])
 | |
| 				ecommunity_free(
 | |
| 						&bgp->vpn_policy[afi].rtlist[dir]);
 | |
| 			bgp->vpn_policy[afi].rtlist[dir] = NULL;
 | |
| 		}
 | |
| 
 | |
| 		vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
 | |
| 	}
 | |
| 
 | |
| 	if (ecom)
 | |
| 		ecommunity_free(&ecom);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS (af_rt_vpn_imexport,
 | |
|        af_no_rt_vpn_imexport_cmd,
 | |
|        "no <rt|route-target> vpn <import|export|both>$direction_str",
 | |
|        NO_STR
 | |
|        "Specify route target list\n"
 | |
|        "Specify route target list\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from vpn to current address-family\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "both import and export\n")
 | |
| 
 | |
| DEFPY (af_route_map_vpn_imexport,
 | |
|        af_route_map_vpn_imexport_cmd,
 | |
| /* future: "route-map <vpn|evpn|vrf NAME> <import|export> RMAP" */
 | |
|        "[no] route-map vpn <import|export>$direction_str RMAP$rmap_str",
 | |
|        NO_STR
 | |
|        "Specify route map\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from vpn to current address-family\n"
 | |
|        "For routes leaked from current address-family to vpn\n"
 | |
|        "name of route-map\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 	int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
 | |
| 	enum vpn_policy_direction dir;
 | |
| 	afi_t afi;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	ret = vpn_policy_getdirs(vty, direction_str, dodir);
 | |
| 	if (ret != CMD_SUCCESS)
 | |
| 		return ret;
 | |
| 
 | |
| 	for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
 | |
| 		if (!dodir[dir])
 | |
| 			continue;
 | |
| 
 | |
| 		vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 		if (yes) {
 | |
| 			if (bgp->vpn_policy[afi].rmap_name[dir])
 | |
| 				XFREE(MTYPE_ROUTE_MAP_NAME,
 | |
| 				      bgp->vpn_policy[afi].rmap_name[dir]);
 | |
| 			bgp->vpn_policy[afi].rmap_name[dir] = XSTRDUP(
 | |
| 								      MTYPE_ROUTE_MAP_NAME, rmap_str);
 | |
| 			bgp->vpn_policy[afi].rmap[dir] =
 | |
| 				route_map_lookup_warn_noexist(vty, rmap_str);
 | |
| 			if (!bgp->vpn_policy[afi].rmap[dir])
 | |
| 				return CMD_SUCCESS;
 | |
| 		} else {
 | |
| 			if (bgp->vpn_policy[afi].rmap_name[dir])
 | |
| 				XFREE(MTYPE_ROUTE_MAP_NAME,
 | |
| 				      bgp->vpn_policy[afi].rmap_name[dir]);
 | |
| 			bgp->vpn_policy[afi].rmap_name[dir] = NULL;
 | |
| 			bgp->vpn_policy[afi].rmap[dir] = NULL;
 | |
| 		}
 | |
| 
 | |
| 		vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS (af_route_map_vpn_imexport,
 | |
|        af_no_route_map_vpn_imexport_cmd,
 | |
|        "no route-map vpn <import|export>$direction_str",
 | |
|        NO_STR
 | |
|        "Specify route map\n"
 | |
|        "Between current address-family and vpn\n"
 | |
|        "For routes leaked from vpn to current address-family\n"
 | |
|        "For routes leaked from current address-family to vpn\n")
 | |
| 
 | |
| DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
 | |
|       "import vrf route-map RMAP$rmap_str",
 | |
|       "Import routes from another VRF\n"
 | |
|       "Vrf routes being filtered\n"
 | |
|       "Specify route map\n"
 | |
|       "name of route-map\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	enum vpn_policy_direction dir = BGP_VPN_POLICY_DIR_FROMVPN;
 | |
| 	afi_t afi;
 | |
| 	struct bgp *bgp_default;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, true);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp_default = bgp_get_default();
 | |
| 	if (!bgp_default) {
 | |
| 		int32_t ret;
 | |
| 		as_t as = bgp->as;
 | |
| 
 | |
| 		/* Auto-create assuming the same AS */
 | |
| 		ret = bgp_get_vty(&bgp_default, &as, NULL,
 | |
| 				  BGP_INSTANCE_TYPE_DEFAULT, NULL,
 | |
| 				  ASNOTATION_UNDEFINED);
 | |
| 
 | |
| 		if (ret) {
 | |
| 			vty_out(vty,
 | |
| 				"VRF default is not configured as a bgp instance\n");
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].rmap_name[dir])
 | |
| 		XFREE(MTYPE_ROUTE_MAP_NAME,
 | |
| 		      bgp->vpn_policy[afi].rmap_name[dir]);
 | |
| 	bgp->vpn_policy[afi].rmap_name[dir] =
 | |
| 		XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
 | |
| 	bgp->vpn_policy[afi].rmap[dir] =
 | |
| 		route_map_lookup_warn_noexist(vty, rmap_str);
 | |
| 	if (!bgp->vpn_policy[afi].rmap[dir])
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	SET_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 		 BGP_CONFIG_VRF_TO_VRF_IMPORT);
 | |
| 
 | |
| 	vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(af_no_import_vrf_route_map, af_no_import_vrf_route_map_cmd,
 | |
|       "no import vrf route-map [RMAP$rmap_str]",
 | |
|       NO_STR
 | |
|       "Import routes from another VRF\n"
 | |
|       "Vrf routes being filtered\n"
 | |
|       "Specify route map\n"
 | |
|       "name of route-map\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	enum vpn_policy_direction dir = BGP_VPN_POLICY_DIR_FROMVPN;
 | |
| 	afi_t afi;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, true);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].rmap_name[dir])
 | |
| 		XFREE(MTYPE_ROUTE_MAP_NAME,
 | |
| 		      bgp->vpn_policy[afi].rmap_name[dir]);
 | |
| 	bgp->vpn_policy[afi].rmap_name[dir] = NULL;
 | |
| 	bgp->vpn_policy[afi].rmap[dir] = NULL;
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].import_vrf->count == 0)
 | |
| 		UNSET_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 			   BGP_CONFIG_VRF_TO_VRF_IMPORT);
 | |
| 
 | |
| 	vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
 | |
|       "[no] import vrf VIEWVRFNAME$import_name",
 | |
|       NO_STR
 | |
|       "Import routes from another VRF\n"
 | |
|       "VRF to import from\n"
 | |
|       "The name of the VRF\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	struct listnode *node;
 | |
| 	struct bgp *vrf_bgp, *bgp_default;
 | |
| 	int32_t ret = 0;
 | |
| 	as_t as = bgp->as;
 | |
| 	bool remove = false;
 | |
| 	int32_t idx = 0;
 | |
| 	char *vname;
 | |
| 	enum bgp_instance_type bgp_type = BGP_INSTANCE_TYPE_VRF;
 | |
| 	safi_t safi;
 | |
| 	afi_t afi;
 | |
| 
 | |
| 	if (import_name == NULL) {
 | |
| 		vty_out(vty, "%% Missing import name\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	if (strcmp(import_name, "route-map") == 0) {
 | |
| 		vty_out(vty, "%% Must include route-map name\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		remove = true;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, true);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	safi = bgp_node_safi(vty);
 | |
| 
 | |
| 	if (((BGP_INSTANCE_TYPE_DEFAULT == bgp->inst_type)
 | |
| 	     && (strcmp(import_name, VRF_DEFAULT_NAME) == 0))
 | |
| 	    || (bgp->name && (strcmp(import_name, bgp->name) == 0))) {
 | |
| 		vty_out(vty, "%% Cannot %s vrf %s into itself\n",
 | |
| 			remove ? "unimport" : "import", import_name);
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	bgp_default = bgp_get_default();
 | |
| 	if (!bgp_default) {
 | |
| 		/* Auto-create assuming the same AS */
 | |
| 		ret = bgp_get_vty(&bgp_default, &as, NULL,
 | |
| 				  BGP_INSTANCE_TYPE_DEFAULT, NULL,
 | |
| 				  ASNOTATION_UNDEFINED);
 | |
| 
 | |
| 		if (ret) {
 | |
| 			vty_out(vty,
 | |
| 				"VRF default is not configured as a bgp instance\n");
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	vrf_bgp = bgp_lookup_by_name(import_name);
 | |
| 	if (!vrf_bgp) {
 | |
| 		if (strcmp(import_name, VRF_DEFAULT_NAME) == 0)
 | |
| 			vrf_bgp = bgp_default;
 | |
| 		else
 | |
| 			/* Auto-create assuming the same AS */
 | |
| 			ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
 | |
| 					  NULL, ASNOTATION_UNDEFINED);
 | |
| 		if (ret) {
 | |
| 			vty_out(vty,
 | |
| 				"VRF %s is not configured as a bgp instance\n",
 | |
| 				import_name);
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (remove) {
 | |
| 		vrf_unimport_from_vrf(bgp, vrf_bgp, afi, safi);
 | |
| 	} else {
 | |
| 		/* Already importing from "import_vrf"? */
 | |
| 		for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
 | |
| 					  vname)) {
 | |
| 			if (strcmp(vname, import_name) == 0)
 | |
| 				return CMD_WARNING;
 | |
| 		}
 | |
| 
 | |
| 		vrf_import_from_vrf(bgp, vrf_bgp, afi, safi);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* This command is valid only in a bgp vrf instance or the default instance */
 | |
| DEFPY (bgp_imexport_vpn,
 | |
|        bgp_imexport_vpn_cmd,
 | |
|        "[no] <import|export>$direction_str vpn",
 | |
|        NO_STR
 | |
|        "Import routes to this address-family\n"
 | |
|        "Export routes from this address-family\n"
 | |
|        "to/from default instance VPN RIB\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int previous_state;
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	int idx = 0;
 | |
| 	bool yes = true;
 | |
| 	int flag;
 | |
| 	enum vpn_policy_direction dir;
 | |
| 	struct bgp *bgp_default = bgp_get_default();
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type &&
 | |
| 		BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
 | |
| 
 | |
| 		vty_out(vty, "%% import|export vpn valid only for bgp vrf or default instance\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	afi = bgp_node_afi(vty);
 | |
| 	safi = bgp_node_safi(vty);
 | |
| 	if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
 | |
| 		vty_out(vty, "%% import|export vpn valid only for unicast ipv4|ipv6\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	if (!strcmp(direction_str, "import")) {
 | |
| 		flag = BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT;
 | |
| 		dir = BGP_VPN_POLICY_DIR_FROMVPN;
 | |
| 	} else if (!strcmp(direction_str, "export")) {
 | |
| 		flag = BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT;
 | |
| 		dir = BGP_VPN_POLICY_DIR_TOVPN;
 | |
| 	} else {
 | |
| 		vty_out(vty, "%% unknown direction %s\n", direction_str);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	previous_state = CHECK_FLAG(bgp->af_flags[afi][safi], flag);
 | |
| 
 | |
| 	if (yes) {
 | |
| 		SET_FLAG(bgp->af_flags[afi][safi], flag);
 | |
| 		if (!previous_state) {
 | |
| 			/* trigger export current vrf */
 | |
| 			vpn_leak_postchange(dir, afi, bgp_default, bgp);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (previous_state) {
 | |
| 			/* trigger un-export current vrf */
 | |
| 			vpn_leak_prechange(dir, afi, bgp_default, bgp);
 | |
| 		}
 | |
| 		UNSET_FLAG(bgp->af_flags[afi][safi], flag);
 | |
| 		if (previous_state && bgp_default &&
 | |
| 		    !CHECK_FLAG(bgp_default->af_flags[afi][SAFI_MPLS_VPN],
 | |
| 				BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
 | |
| 			vpn_leak_no_retain(bgp, bgp_default, afi);
 | |
| 	}
 | |
| 
 | |
| 	hook_call(bgp_snmp_init_stats, bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (af_routetarget_import,
 | |
|        af_routetarget_import_cmd,
 | |
|        "[no] <rt|route-target|route-target6|rt6> redirect import RTLIST...",
 | |
|        NO_STR
 | |
|        "Specify route target list\n"
 | |
|        "Specify route target list\n"
 | |
|        "Specify route target list\n"
 | |
|        "Specify route target list\n"
 | |
|        "Flow-spec redirect type route target\n"
 | |
|        "Import routes to this address-family\n"
 | |
|        "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN|IPV6:MN)\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 	struct ecommunity *ecom = NULL;
 | |
| 	afi_t afi;
 | |
| 	int idx = 0, idx_unused = 0;
 | |
| 	bool yes = true;
 | |
| 	bool rt6 = false;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "no", &idx))
 | |
| 		yes = false;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "rt6", &idx_unused) ||
 | |
| 	    argv_find(argv, argc, "route-target6", &idx_unused))
 | |
| 		rt6 = true;
 | |
| 
 | |
| 	afi = vpn_policy_getafi(vty, bgp, false);
 | |
| 	if (afi == AFI_MAX)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (rt6 && afi != AFI_IP6)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (yes) {
 | |
| 		if (!argv_find(argv, argc, "RTLIST", &idx)) {
 | |
| 			vty_out(vty, "%% Missing RTLIST\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		ret = set_ecom_list(vty, argc - idx, argv + idx, &ecom, rt6);
 | |
| 		if (ret != CMD_SUCCESS)
 | |
| 			return ret;
 | |
| 	}
 | |
| 
 | |
| 	if (yes) {
 | |
| 		if (bgp->vpn_policy[afi].import_redirect_rtlist)
 | |
| 			ecommunity_free(&bgp->vpn_policy[afi]
 | |
| 					.import_redirect_rtlist);
 | |
| 		bgp->vpn_policy[afi].import_redirect_rtlist =
 | |
| 			ecommunity_dup(ecom);
 | |
| 	} else {
 | |
| 		if (bgp->vpn_policy[afi].import_redirect_rtlist)
 | |
| 			ecommunity_free(&bgp->vpn_policy[afi]
 | |
| 					.import_redirect_rtlist);
 | |
| 		bgp->vpn_policy[afi].import_redirect_rtlist = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (ecom)
 | |
| 		ecommunity_free(&ecom);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_NOSH (address_family_ipv4_safi,
 | |
| 	address_family_ipv4_safi_cmd,
 | |
| 	"address-family ipv4 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
 | |
| 	"Enter Address Family command mode\n"
 | |
| 	BGP_AF_STR
 | |
| 	BGP_SAFI_WITH_LABEL_HELP_STR)
 | |
| {
 | |
| 
 | |
| 	if (argc == 3) {
 | |
| 		VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 		safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
 | |
| 		if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
 | |
| 		    && safi != SAFI_UNICAST && safi != SAFI_MULTICAST
 | |
| 		    && safi != SAFI_EVPN) {
 | |
| 			vty_out(vty,
 | |
| 				"Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		vty->node = bgp_node_type(AFI_IP, safi);
 | |
| 	} else
 | |
| 		vty->node = BGP_IPV4_NODE;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_NOSH (address_family_ipv6_safi,
 | |
| 	address_family_ipv6_safi_cmd,
 | |
| 	"address-family ipv6 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
 | |
| 	"Enter Address Family command mode\n"
 | |
| 	BGP_AF_STR
 | |
| 	BGP_SAFI_WITH_LABEL_HELP_STR)
 | |
| {
 | |
| 	if (argc == 3) {
 | |
| 		VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 		safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
 | |
| 		if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
 | |
| 		    && safi != SAFI_UNICAST && safi != SAFI_MULTICAST
 | |
| 		    && safi != SAFI_EVPN) {
 | |
| 			vty_out(vty,
 | |
| 				"Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 		}
 | |
| 		vty->node = bgp_node_type(AFI_IP6, safi);
 | |
| 	} else
 | |
| 		vty->node = BGP_IPV6_NODE;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| #ifdef KEEP_OLD_VPN_COMMANDS
 | |
| DEFUN_NOSH (address_family_vpnv4,
 | |
|        address_family_vpnv4_cmd,
 | |
|        "address-family vpnv4 [unicast]",
 | |
|        "Enter Address Family command mode\n"
 | |
|        BGP_AF_STR
 | |
|        BGP_AF_MODIFIER_STR)
 | |
| {
 | |
| 	vty->node = BGP_VPNV4_NODE;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_NOSH (address_family_vpnv6,
 | |
|        address_family_vpnv6_cmd,
 | |
|        "address-family vpnv6 [unicast]",
 | |
|        "Enter Address Family command mode\n"
 | |
|        BGP_AF_STR
 | |
|        BGP_AF_MODIFIER_STR)
 | |
| {
 | |
| 	vty->node = BGP_VPNV6_NODE;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| #endif /* KEEP_OLD_VPN_COMMANDS */
 | |
| 
 | |
| DEFUN_NOSH (address_family_evpn,
 | |
|        address_family_evpn_cmd,
 | |
|        "address-family l2vpn evpn",
 | |
|        "Enter Address Family command mode\n"
 | |
|        BGP_AF_STR
 | |
|        BGP_AF_MODIFIER_STR)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	vty->node = BGP_EVPN_NODE;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_NOSH (bgp_segment_routing_srv6,
 | |
|             bgp_segment_routing_srv6_cmd,
 | |
|             "segment-routing srv6",
 | |
|             "Segment-Routing configuration\n"
 | |
|             "Segment-Routing SRv6 configuration\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	bgp->srv6_enabled = true;
 | |
| 	vty->node = BGP_SRV6_NODE;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_segment_routing_srv6,
 | |
|        no_bgp_segment_routing_srv6_cmd,
 | |
|        "no segment-routing srv6",
 | |
|        NO_STR
 | |
|        "Segment-Routing configuration\n"
 | |
|        "Segment-Routing SRv6 configuration\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	if (strlen(bgp->srv6_locator_name) > 0)
 | |
| 		if (bgp_srv6_locator_unset(bgp) < 0)
 | |
| 			return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	bgp->srv6_enabled = false;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_srv6_locator,
 | |
|        bgp_srv6_locator_cmd,
 | |
|        "locator NAME$name",
 | |
|        "Specify SRv6 locator\n"
 | |
|        "Specify SRv6 locator\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int ret;
 | |
| 
 | |
| 	if (strlen(bgp->srv6_locator_name) > 0
 | |
| 	    && strcmp(name, bgp->srv6_locator_name) != 0) {
 | |
| 		vty_out(vty, "srv6 locator is already configured\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	snprintf(bgp->srv6_locator_name,
 | |
| 		 sizeof(bgp->srv6_locator_name), "%s", name);
 | |
| 
 | |
| 	ret = bgp_zebra_srv6_manager_get_locator_chunk(name);
 | |
| 	if (ret < 0)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_srv6_locator,
 | |
|        no_bgp_srv6_locator_cmd,
 | |
|        "no locator NAME$name",
 | |
|        NO_STR
 | |
|        "Specify SRv6 locator\n"
 | |
|        "Specify SRv6 locator\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 
 | |
| 	/* when locator isn't configured, do nothing */
 | |
| 	if (strlen(bgp->srv6_locator_name) < 1)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	/* name validation */
 | |
| 	if (strcmp(name, bgp->srv6_locator_name) != 0) {
 | |
| 		vty_out(vty, "%% No srv6 locator is configured\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	/* unset locator */
 | |
| 	if (bgp_srv6_locator_unset(bgp) < 0)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (show_bgp_srv6,
 | |
|        show_bgp_srv6_cmd,
 | |
|        "show bgp segment-routing srv6",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "BGP Segment Routing\n"
 | |
|        "BGP Segment Routing SRv6\n")
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct listnode *node;
 | |
| 	struct srv6_locator_chunk *chunk;
 | |
| 	struct bgp_srv6_function *func;
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 	if (!bgp)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name);
 | |
| 	vty_out(vty, "locator_chunks:\n");
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
 | |
| 		vty_out(vty, "- %pFX\n", &chunk->prefix);
 | |
| 		vty_out(vty, "  block-length: %d\n", chunk->block_bits_length);
 | |
| 		vty_out(vty, "  node-length: %d\n", chunk->node_bits_length);
 | |
| 		vty_out(vty, "  func-length: %d\n",
 | |
| 			chunk->function_bits_length);
 | |
| 		vty_out(vty, "  arg-length: %d\n", chunk->argument_bits_length);
 | |
| 	}
 | |
| 
 | |
| 	vty_out(vty, "functions:\n");
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) {
 | |
| 		vty_out(vty, "- sid: %pI6\n", &func->sid);
 | |
| 		vty_out(vty, "  locator: %s\n", func->locator_name);
 | |
| 	}
 | |
| 
 | |
| 	vty_out(vty, "bgps:\n");
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
 | |
| 		vty_out(vty, "- name: %s\n",
 | |
| 			bgp->name ? bgp->name : "default");
 | |
| 
 | |
| 		vty_out(vty, "  vpn_policy[AFI_IP].tovpn_sid: %pI6\n",
 | |
| 			bgp->vpn_policy[AFI_IP].tovpn_sid);
 | |
| 		vty_out(vty, "  vpn_policy[AFI_IP6].tovpn_sid: %pI6\n",
 | |
| 			bgp->vpn_policy[AFI_IP6].tovpn_sid);
 | |
| 		vty_out(vty, "  per-vrf tovpn_sid: %pI6\n", bgp->tovpn_sid);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN_NOSH (exit_address_family,
 | |
|        exit_address_family_cmd,
 | |
|        "exit-address-family",
 | |
|        "Exit from Address Family configuration mode\n")
 | |
| {
 | |
| 	if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE
 | |
| 	    || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE
 | |
| 	    || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE
 | |
| 	    || vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE
 | |
| 	    || vty->node == BGP_EVPN_NODE
 | |
| 	    || vty->node == BGP_FLOWSPECV4_NODE
 | |
| 	    || vty->node == BGP_FLOWSPECV6_NODE)
 | |
| 		vty->node = BGP_NODE;
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Recalculate bestpath and re-advertise a prefix */
 | |
| static int bgp_clear_prefix(struct vty *vty, const char *view_name,
 | |
| 			    const char *ip_str, afi_t afi, safi_t safi,
 | |
| 			    struct prefix_rd *prd)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct prefix match;
 | |
| 	struct bgp_dest *dest;
 | |
| 	struct bgp_dest *rm;
 | |
| 	struct bgp *bgp;
 | |
| 	struct bgp_table *table;
 | |
| 	struct bgp_table *rib;
 | |
| 
 | |
| 	/* BGP structure lookup. */
 | |
| 	if (view_name) {
 | |
| 		bgp = bgp_lookup_by_name(view_name);
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "%% Can't find BGP instance %s\n",
 | |
| 				view_name);
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	} else {
 | |
| 		bgp = bgp_get_default();
 | |
| 		if (bgp == NULL) {
 | |
| 			vty_out(vty, "%% No BGP process is configured\n");
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Check IP address argument. */
 | |
| 	ret = str2prefix(ip_str, &match);
 | |
| 	if (!ret) {
 | |
| 		vty_out(vty, "%% address is malformed\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	match.family = afi2family(afi);
 | |
| 	rib = bgp->rib[afi][safi];
 | |
| 
 | |
| 	if (safi == SAFI_MPLS_VPN) {
 | |
| 		for (dest = bgp_table_top(rib); dest;
 | |
| 		     dest = bgp_route_next(dest)) {
 | |
| 			const struct prefix *dest_p = bgp_dest_get_prefix(dest);
 | |
| 
 | |
| 			if (prd && memcmp(dest_p->u.val, prd->val, 8) != 0)
 | |
| 				continue;
 | |
| 
 | |
| 			table = bgp_dest_get_bgp_table_info(dest);
 | |
| 			if (table == NULL)
 | |
| 				continue;
 | |
| 
 | |
| 			rm = bgp_node_match(table, &match);
 | |
| 			if (rm != NULL) {
 | |
| 				const struct prefix *rm_p =
 | |
| 					bgp_dest_get_prefix(rm);
 | |
| 
 | |
| 				if (rm_p->prefixlen == match.prefixlen) {
 | |
| 					SET_FLAG(rm->flags,
 | |
| 						 BGP_NODE_USER_CLEAR);
 | |
| 					bgp_process(bgp, rm, afi, safi);
 | |
| 				}
 | |
| 				bgp_dest_unlock_node(rm);
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		dest = bgp_node_match(rib, &match);
 | |
| 		if (dest != NULL) {
 | |
| 			const struct prefix *dest_p = bgp_dest_get_prefix(dest);
 | |
| 
 | |
| 			if (dest_p->prefixlen == match.prefixlen) {
 | |
| 				SET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
 | |
| 				bgp_process(bgp, dest, afi, safi);
 | |
| 			}
 | |
| 			bgp_dest_unlock_node(dest);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* one clear bgp command to rule them all */
 | |
| DEFUN (clear_ip_bgp_all,
 | |
|        clear_ip_bgp_all_cmd,
 | |
|        "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
 | |
|        CLEAR_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        BGP_AFI_HELP_STR
 | |
|        BGP_AF_STR
 | |
|        BGP_SAFI_WITH_LABEL_HELP_STR
 | |
|        BGP_AF_MODIFIER_STR
 | |
|        "Clear all peers\n"
 | |
|        "BGP IPv4 neighbor to clear\n"
 | |
|        "BGP IPv6 neighbor to clear\n"
 | |
|        "BGP neighbor on interface to clear\n"
 | |
|        "Clear peers with the AS number in plain or dotted format\n"
 | |
|        "Clear all external peers\n"
 | |
|        "Clear all members of peer-group\n"
 | |
|        "BGP peer-group name\n"
 | |
|        BGP_SOFT_STR
 | |
|        BGP_SOFT_IN_STR
 | |
|        BGP_SOFT_OUT_STR
 | |
|        BGP_SOFT_IN_STR
 | |
|        "Push out prefix-list ORF and do inbound soft reconfig\n"
 | |
|        BGP_SOFT_OUT_STR
 | |
|        "Reset message statistics\n")
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 
 | |
| 	afi_t afi = AFI_UNSPEC;
 | |
| 	safi_t safi = SAFI_UNSPEC;
 | |
| 	enum clear_sort clr_sort = clear_peer;
 | |
| 	enum bgp_clear_type clr_type;
 | |
| 	char *clr_arg = NULL;
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	/* clear [ip] bgp */
 | |
| 	if (argv_find(argv, argc, "ip", &idx))
 | |
| 		afi = AFI_IP;
 | |
| 
 | |
| 	/* [<vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		idx += 2;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx)) {
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		idx += 2;
 | |
| 	}
 | |
| 	/* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */
 | |
| 	if (argv_find_and_parse_afi(argv, argc, &idx, &afi))
 | |
| 		argv_find_and_parse_safi(argv, argc, &idx, &safi);
 | |
| 
 | |
| 	/* <*|A.B.C.D|X:X::X:X|WORD|ASNUM|external|peer-group PGNAME> */
 | |
| 	if (argv_find(argv, argc, "*", &idx)) {
 | |
| 		clr_sort = clear_all;
 | |
| 	} else if (argv_find(argv, argc, "A.B.C.D", &idx)) {
 | |
| 		clr_sort = clear_peer;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "X:X::X:X", &idx)) {
 | |
| 		clr_sort = clear_peer;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "peer-group", &idx)) {
 | |
| 		clr_sort = clear_group;
 | |
| 		idx++;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "PGNAME", &idx)) {
 | |
| 		clr_sort = clear_peer;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "WORD", &idx)) {
 | |
| 		clr_sort = clear_peer;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "ASNUM", &idx)) {
 | |
| 		clr_sort = clear_as;
 | |
| 		clr_arg = argv[idx]->arg;
 | |
| 	} else if (argv_find(argv, argc, "external", &idx)) {
 | |
| 		clr_sort = clear_external;
 | |
| 	}
 | |
| 
 | |
| 	/* [<soft [<in|out>]|in [prefix-filter]|out|message-stats>] */
 | |
| 	if (argv_find(argv, argc, "soft", &idx)) {
 | |
| 		if (argv_find(argv, argc, "in", &idx)
 | |
| 		    || argv_find(argv, argc, "out", &idx))
 | |
| 			clr_type = strmatch(argv[idx]->text, "in")
 | |
| 					   ? BGP_CLEAR_SOFT_IN
 | |
| 					   : BGP_CLEAR_SOFT_OUT;
 | |
| 		else
 | |
| 			clr_type = BGP_CLEAR_SOFT_BOTH;
 | |
| 	} else if (argv_find(argv, argc, "in", &idx)) {
 | |
| 		clr_type = argv_find(argv, argc, "prefix-filter", &idx)
 | |
| 				   ? BGP_CLEAR_SOFT_IN_ORF_PREFIX
 | |
| 				   : BGP_CLEAR_SOFT_IN;
 | |
| 	} else if (argv_find(argv, argc, "out", &idx)) {
 | |
| 		clr_type = BGP_CLEAR_SOFT_OUT;
 | |
| 	} else if (argv_find(argv, argc, "message-stats", &idx)) {
 | |
| 		clr_type = BGP_CLEAR_MESSAGE_STATS;
 | |
| 	} else
 | |
| 		clr_type = BGP_CLEAR_SOFT_NONE;
 | |
| 
 | |
| 	return bgp_clear_vty(vty, vrf, afi, safi, clr_sort, clr_type, clr_arg);
 | |
| }
 | |
| 
 | |
| DEFUN (clear_ip_bgp_prefix,
 | |
|        clear_ip_bgp_prefix_cmd,
 | |
|        "clear [ip] bgp [<view|vrf> VIEWVRFNAME] prefix A.B.C.D/M",
 | |
|        CLEAR_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        "Clear bestpath and re-advertise\n"
 | |
|        "IPv4 prefix\n")
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	char *prefix = NULL;
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	/* [<view|vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		idx += 2;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx)) {
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		idx += 2;
 | |
| 	}
 | |
| 
 | |
| 	prefix = argv[argc - 1]->arg;
 | |
| 
 | |
| 	return bgp_clear_prefix(vty, vrf, prefix, AFI_IP, SAFI_UNICAST, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (clear_bgp_ipv6_safi_prefix,
 | |
|        clear_bgp_ipv6_safi_prefix_cmd,
 | |
|        "clear [ip] bgp ipv6 "BGP_SAFI_CMD_STR" prefix X:X::X:X/M",
 | |
|        CLEAR_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_AF_STR
 | |
|        BGP_SAFI_HELP_STR
 | |
|        "Clear bestpath and re-advertise\n"
 | |
|        "IPv6 prefix\n")
 | |
| {
 | |
| 	int idx_safi = 0;
 | |
| 	int idx_ipv6_prefix = 0;
 | |
| 	safi_t safi = SAFI_UNICAST;
 | |
| 	char *prefix = argv_find(argv, argc, "X:X::X:X/M", &idx_ipv6_prefix) ?
 | |
| 		argv[idx_ipv6_prefix]->arg : NULL;
 | |
| 
 | |
| 	argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
 | |
| 	return bgp_clear_prefix(
 | |
| 		vty, NULL, prefix, AFI_IP6,
 | |
| 		safi, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (clear_bgp_instance_ipv6_safi_prefix,
 | |
|        clear_bgp_instance_ipv6_safi_prefix_cmd,
 | |
|        "clear [ip] bgp <view|vrf> VIEWVRFNAME ipv6 "BGP_SAFI_CMD_STR" prefix X:X::X:X/M",
 | |
|        CLEAR_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        BGP_AF_STR
 | |
|        BGP_SAFI_HELP_STR
 | |
|        "Clear bestpath and re-advertise\n"
 | |
|        "IPv6 prefix\n")
 | |
| {
 | |
| 	int idx_safi = 0;
 | |
| 	int idx_vrfview = 0;
 | |
| 	int idx_ipv6_prefix = 0;
 | |
| 	safi_t safi = SAFI_UNICAST;
 | |
| 	char *prefix = argv_find(argv, argc, "X:X::X:X/M", &idx_ipv6_prefix) ?
 | |
| 		argv[idx_ipv6_prefix]->arg : NULL;
 | |
| 	char *vrfview = NULL;
 | |
| 
 | |
| 	/* [<view|vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx_vrfview)) {
 | |
| 		vrfview = argv[idx_vrfview + 1]->arg;
 | |
| 		if (vrfview && strmatch(vrfview, VRF_DEFAULT_NAME))
 | |
| 			vrfview = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx_vrfview)) {
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrfview = argv[idx_vrfview + 1]->arg;
 | |
| 	}
 | |
| 	argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
 | |
| 
 | |
| 	return bgp_clear_prefix(
 | |
| 		vty, vrfview, prefix,
 | |
| 		AFI_IP6, safi, NULL);
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_views,
 | |
|        show_bgp_views_cmd,
 | |
|        "show [ip] bgp views",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "Show the defined BGP views\n")
 | |
| {
 | |
| 	struct list *inst = bm->bgp;
 | |
| 	struct listnode *node;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	vty_out(vty, "Defined BGP views:\n");
 | |
| 	for (ALL_LIST_ELEMENTS_RO(inst, node, bgp)) {
 | |
| 		/* Skip VRFs. */
 | |
| 		if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
 | |
| 			continue;
 | |
| 		vty_out(vty, "\t%s (AS%s)\n", bgp->name ? bgp->name : "(null)",
 | |
| 			bgp->as_pretty);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static inline void calc_peers_cfgd_estbd(struct bgp *bgp, int *peers_cfgd,
 | |
| 					 int *peers_estbd)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	struct listnode *node;
 | |
| 
 | |
| 	*peers_cfgd = *peers_estbd = 0;
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
 | |
| 		if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 			continue;
 | |
| 		(*peers_cfgd)++;
 | |
| 		if (peer_established(peer))
 | |
| 			(*peers_estbd)++;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void print_bgp_vrfs(struct bgp *bgp, struct vty *vty, json_object *json,
 | |
| 			   const char *type)
 | |
| {
 | |
| 	int peers_cfg, peers_estb;
 | |
| 
 | |
| 	calc_peers_cfgd_estbd(bgp, &peers_cfg, &peers_estb);
 | |
| 
 | |
| 	if (json) {
 | |
| 		int64_t vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN)
 | |
| 					    ? -1
 | |
| 					    : (int64_t)bgp->vrf_id;
 | |
| 		json_object_string_add(json, "type", type);
 | |
| 		json_object_int_add(json, "vrfId", vrf_id_ui);
 | |
| 		json_object_string_addf(json, "routerId", "%pI4",
 | |
| 					&bgp->router_id);
 | |
| 		json_object_int_add(json, "numConfiguredPeers", peers_cfg);
 | |
| 		json_object_int_add(json, "numEstablishedPeers", peers_estb);
 | |
| 		json_object_int_add(json, "l3vni", bgp->l3vni);
 | |
| 		json_object_string_addf(json, "rmac", "%pEA", &bgp->rmac);
 | |
| 		json_object_string_add(
 | |
| 			json, "interface",
 | |
| 			ifindex2ifname(bgp->l3vni_svi_ifindex, bgp->vrf_id));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int show_bgp_vrfs_detail_common(struct vty *vty, struct bgp *bgp,
 | |
| 				       json_object *json, const char *name,
 | |
| 				       const char *type, bool use_vrf)
 | |
| {
 | |
| 	int peers_cfg, peers_estb;
 | |
| 
 | |
| 	calc_peers_cfgd_estbd(bgp, &peers_cfg, &peers_estb);
 | |
| 
 | |
| 	if (use_vrf) {
 | |
| 		if (json) {
 | |
| 			print_bgp_vrfs(bgp, vty, json, type);
 | |
| 		} else {
 | |
| 			vty_out(vty, "BGP instance %s VRF id %d\n",
 | |
| 				bgp->name_pretty,
 | |
| 				bgp->vrf_id == VRF_UNKNOWN ? -1
 | |
| 							   : (int)bgp->vrf_id);
 | |
| 			vty_out(vty, "Router Id %pI4\n", &bgp->router_id);
 | |
| 			vty_out(vty,
 | |
| 				"Num Configured Peers %d, Established %d\n",
 | |
| 				peers_cfg, peers_estb);
 | |
| 			if (bgp->l3vni) {
 | |
| 				vty_out(vty,
 | |
| 					"L3VNI %u, L3VNI-SVI %s, Router MAC %pEA\n",
 | |
| 					bgp->l3vni,
 | |
| 					ifindex2ifname(bgp->l3vni_svi_ifindex,
 | |
| 						       bgp->vrf_id),
 | |
| 					&bgp->rmac);
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (json) {
 | |
| 			print_bgp_vrfs(bgp, vty, json, type);
 | |
| 		} else {
 | |
| 			vty_out(vty, "%4s  %-5d  %-16pI4  %-9u  %-10u  %-37s\n",
 | |
| 				type,
 | |
| 				bgp->vrf_id == VRF_UNKNOWN ? -1
 | |
| 							   : (int)bgp->vrf_id,
 | |
| 				&bgp->router_id, peers_cfg, peers_estb, name);
 | |
| 			vty_out(vty, "%11s  %-16u  %-21pEA  %-20s\n", " ",
 | |
| 				bgp->l3vni, &bgp->rmac,
 | |
| 				ifindex2ifname(bgp->l3vni_svi_ifindex,
 | |
| 					       bgp->vrf_id));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (show_bgp_vrfs,
 | |
|        show_bgp_vrfs_cmd,
 | |
|        "show [ip] bgp vrfs [<VRFNAME$vrf_name>] [json]",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "Show BGP VRFs\n"
 | |
|        "Specific VRF name\n"
 | |
|        JSON_STR)
 | |
| {
 | |
| 	struct list *inst = bm->bgp;
 | |
| 	struct listnode *node;
 | |
| 	struct bgp *bgp;
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 	json_object *json = NULL;
 | |
| 	json_object *json_vrfs = NULL;
 | |
| 	json_object *json_vrf = NULL;
 | |
| 	int count = 0;
 | |
| 	const char *name = vrf_name;
 | |
| 	const char *type;
 | |
| 
 | |
| 	if (uj)
 | |
| 		json = json_object_new_object();
 | |
| 
 | |
| 	if (name) {
 | |
| 		if (strmatch(name, VRF_DEFAULT_NAME)) {
 | |
| 			bgp = bgp_get_default();
 | |
| 			type = "DFLT";
 | |
| 		} else {
 | |
| 			bgp = bgp_lookup_by_name(name);
 | |
| 			type = "VRF";
 | |
| 		}
 | |
| 		if (!bgp) {
 | |
| 			if (uj)
 | |
| 				vty_json(vty, json);
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"%% Specified BGP instance not found\n");
 | |
| 
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (vrf_name) {
 | |
| 		if (uj)
 | |
| 			json_vrf = json_object_new_object();
 | |
| 
 | |
| 		show_bgp_vrfs_detail_common(vty, bgp, json_vrf, name, type,
 | |
| 					    true);
 | |
| 
 | |
| 		if (uj) {
 | |
| 			json_object_object_add(json, name, json_vrf);
 | |
| 			vty_json(vty, json);
 | |
| 		}
 | |
| 
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	if (uj)
 | |
| 		json_vrfs = json_object_new_object();
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(inst, node, bgp)) {
 | |
| 		const char *name;
 | |
| 
 | |
| 		/* Skip Views. */
 | |
| 		if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
 | |
| 			continue;
 | |
| 
 | |
| 		count++;
 | |
| 		if (!uj && count == 1) {
 | |
| 			vty_out(vty,
 | |
| 				"%4s  %-5s  %-16s  %9s  %10s  %-37s\n",
 | |
| 				"Type", "Id", "routerId", "#PeersCfg",
 | |
| 				"#PeersEstb", "Name");
 | |
| 			vty_out(vty, "%11s  %-16s  %-21s  %-6s\n", " ",
 | |
| 				"L3-VNI", "RouterMAC", "Interface");
 | |
| 		}
 | |
| 		if (uj)
 | |
| 			json_vrf = json_object_new_object();
 | |
| 
 | |
| 		if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
 | |
| 			name = VRF_DEFAULT_NAME;
 | |
| 			type = "DFLT";
 | |
| 		} else {
 | |
| 			name = bgp->name;
 | |
| 			type = "VRF";
 | |
| 		}
 | |
| 
 | |
| 		show_bgp_vrfs_detail_common(vty, bgp, json_vrf, name, type,
 | |
| 					    false);
 | |
| 
 | |
| 		if (uj)
 | |
| 			json_object_object_add(json_vrfs, name, json_vrf);
 | |
| 	}
 | |
| 
 | |
| 	if (uj) {
 | |
| 		json_object_object_add(json, "vrfs", json_vrfs);
 | |
| 		json_object_int_add(json, "totalVrfs", count);
 | |
| 		vty_json(vty, json);
 | |
| 	} else {
 | |
| 		if (count)
 | |
| 			vty_out(vty,
 | |
| 				"\nTotal number of VRFs (including default): %d\n",
 | |
| 				count);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_mac_hash,
 | |
|        show_bgp_mac_hash_cmd,
 | |
|        "show bgp mac hash",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "Mac Address\n"
 | |
|        "Mac Address database\n")
 | |
| {
 | |
| 	bgp_mac_dump_table(vty);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void show_tip_entry(struct hash_bucket *bucket, void *args)
 | |
| {
 | |
| 	struct vty *vty = (struct vty *)args;
 | |
| 	struct tip_addr *tip = (struct tip_addr *)bucket->data;
 | |
| 
 | |
| 	vty_out(vty, "addr: %pI4, count: %d\n", &tip->addr, tip->refcnt);
 | |
| }
 | |
| 
 | |
| static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp)
 | |
| {
 | |
| 	vty_out(vty, "self nexthop database:\n");
 | |
| 	bgp_nexthop_show_address_hash(vty, bgp);
 | |
| 
 | |
| 	vty_out(vty, "Tunnel-ip database:\n");
 | |
| 	hash_iterate(bgp->tip_hash,
 | |
| 		     (void (*)(struct hash_bucket *, void *))show_tip_entry,
 | |
| 		     vty);
 | |
| }
 | |
| 
 | |
| DEFUN(show_bgp_martian_nexthop_db, show_bgp_martian_nexthop_db_cmd,
 | |
|       "show bgp [<view|vrf> VIEWVRFNAME] martian next-hop",
 | |
|       SHOW_STR BGP_STR BGP_INSTANCE_HELP_STR
 | |
|       "martian next-hops\n"
 | |
|       "martian next-hop database\n")
 | |
| {
 | |
| 	struct bgp *bgp = NULL;
 | |
| 	int idx = 0;
 | |
| 	char *name = NULL;
 | |
| 
 | |
| 	/* [<vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		name = argv[idx + 1]->arg;
 | |
| 		if (name && strmatch(name, VRF_DEFAULT_NAME))
 | |
| 			name = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx))
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		name = argv[idx + 1]->arg;
 | |
| 	if (name)
 | |
| 		bgp = bgp_lookup_by_name(name);
 | |
| 	else
 | |
| 		bgp = bgp_get_default();
 | |
| 
 | |
| 	if (!bgp) {
 | |
| 		vty_out(vty, "%% No BGP process is configured\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 	bgp_show_martian_nexthops(vty, bgp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_memory,
 | |
|        show_bgp_memory_cmd,
 | |
|        "show [ip] bgp memory",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "Global BGP memory statistics\n")
 | |
| {
 | |
| 	char memstrbuf[MTYPE_MEMSTR_LEN];
 | |
| 	unsigned long count;
 | |
| 
 | |
| 	/* RIB related usage stats */
 | |
| 	count = mtype_stats_alloc(MTYPE_BGP_NODE);
 | |
| 	vty_out(vty, "%ld RIB nodes, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct bgp_dest)));
 | |
| 
 | |
| 	count = mtype_stats_alloc(MTYPE_BGP_ROUTE);
 | |
| 	vty_out(vty, "%ld BGP routes, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct bgp_path_info)));
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_ROUTE_EXTRA)))
 | |
| 		vty_out(vty, "%ld BGP route ancillaries, using %s of memory\n",
 | |
| 			count,
 | |
| 			mtype_memstr(
 | |
| 				memstrbuf, sizeof(memstrbuf),
 | |
| 				count * sizeof(struct bgp_path_info_extra)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_STATIC)))
 | |
| 		vty_out(vty, "%ld Static routes, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bgp_static)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_PACKET)))
 | |
| 		vty_out(vty, "%ld Packets, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bpacket)));
 | |
| 
 | |
| 	/* Adj-In/Out */
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_ADJ_IN)))
 | |
| 		vty_out(vty, "%ld Adj-In entries, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bgp_adj_in)));
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_ADJ_OUT)))
 | |
| 		vty_out(vty, "%ld Adj-Out entries, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bgp_adj_out)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_NEXTHOP_CACHE)))
 | |
| 		vty_out(vty, "%ld Nexthop cache entries, using %s of memory\n",
 | |
| 			count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bgp_nexthop_cache)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_DAMP_INFO)))
 | |
| 		vty_out(vty, "%ld Dampening entries, using %s of memory\n",
 | |
| 			count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct bgp_damp_info)));
 | |
| 
 | |
| 	/* Attributes */
 | |
| 	count = attr_count();
 | |
| 	vty_out(vty, "%ld BGP attributes, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct attr)));
 | |
| 
 | |
| 	if ((count = attr_unknown_count()))
 | |
| 		vty_out(vty, "%ld unknown attributes\n", count);
 | |
| 
 | |
| 	/* AS_PATH attributes */
 | |
| 	count = aspath_count();
 | |
| 	vty_out(vty, "%ld BGP AS-PATH entries, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct aspath)));
 | |
| 
 | |
| 	count = mtype_stats_alloc(MTYPE_AS_SEG);
 | |
| 	vty_out(vty, "%ld BGP AS-PATH segments, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct assegment)));
 | |
| 
 | |
| 	/* Other attributes */
 | |
| 	if ((count = community_count()))
 | |
| 		vty_out(vty, "%ld BGP community entries, using %s of memory\n",
 | |
| 			count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 					    count * sizeof(struct community)));
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_ECOMMUNITY)))
 | |
| 		vty_out(vty,
 | |
| 			"%ld BGP ext-community entries, using %s of memory\n",
 | |
| 			count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct ecommunity)));
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_LCOMMUNITY)))
 | |
| 		vty_out(vty,
 | |
| 			"%ld BGP large-community entries, using %s of memory\n",
 | |
| 			count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 					    count * sizeof(struct lcommunity)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_CLUSTER)))
 | |
| 		vty_out(vty, "%ld Cluster lists, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct cluster_list)));
 | |
| 
 | |
| 	/* Peer related usage */
 | |
| 	count = mtype_stats_alloc(MTYPE_BGP_PEER);
 | |
| 	vty_out(vty, "%ld peers, using %s of memory\n", count,
 | |
| 		mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 			     count * sizeof(struct peer)));
 | |
| 
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_PEER_GROUP)))
 | |
| 		vty_out(vty, "%ld peer groups, using %s of memory\n", count,
 | |
| 			mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 				     count * sizeof(struct peer_group)));
 | |
| 
 | |
| 	/* Other */
 | |
| 	if ((count = mtype_stats_alloc(MTYPE_BGP_REGEXP)))
 | |
| 		vty_out(vty, "%ld compiled regexes, using %s of memory\n",
 | |
| 			count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
 | |
| 					    count * sizeof(regex_t)));
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json)
 | |
| {
 | |
| 	json_object *bestpath = json_object_new_object();
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE))
 | |
| 		json_object_string_add(bestpath, "asPath", "ignore");
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED))
 | |
| 		json_object_string_add(bestpath, "asPath", "confed");
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET))
 | |
| 			json_object_string_add(bestpath, "multiPathRelax",
 | |
| 					       "as-set");
 | |
| 		else
 | |
| 			json_object_string_add(bestpath, "multiPathRelax",
 | |
| 					       "true");
 | |
| 	} else
 | |
| 		json_object_string_add(bestpath, "multiPathRelax", "false");
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
 | |
| 		json_object_boolean_true_add(bestpath, "peerTypeRelax");
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
 | |
| 		json_object_string_add(bestpath, "compareRouterId", "true");
 | |
| 	if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
 | |
| 	    || CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED))
 | |
| 			json_object_string_add(bestpath, "med", "confed");
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST))
 | |
| 			json_object_string_add(bestpath, "med",
 | |
| 					       "missing-as-worst");
 | |
| 		else
 | |
| 			json_object_string_add(bestpath, "med", "true");
 | |
| 	}
 | |
| 
 | |
| 	json_object_object_add(json, "bestPath", bestpath);
 | |
| }
 | |
| 
 | |
| /* Print the error code/subcode for why the peer is down */
 | |
| static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
 | |
| 				json_object *json_peer, bool use_json)
 | |
| {
 | |
| 	const char *code_str;
 | |
| 	const char *subcode_str;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		if (peer->last_reset == PEER_DOWN_NOTIFY_SEND
 | |
| 		    || peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
 | |
| 			char errorcodesubcode_hexstr[5];
 | |
| 			char errorcodesubcode_str[256];
 | |
| 
 | |
| 			code_str = bgp_notify_code_str(peer->notify.code);
 | |
| 			subcode_str = bgp_notify_subcode_str(
 | |
| 					 peer->notify.code,
 | |
| 					 peer->notify.subcode);
 | |
| 
 | |
| 			snprintf(errorcodesubcode_hexstr,
 | |
| 				 sizeof(errorcodesubcode_hexstr), "%02X%02X",
 | |
| 				 peer->notify.code, peer->notify.subcode);
 | |
| 			json_object_string_add(json_peer,
 | |
| 					       "lastErrorCodeSubcode",
 | |
| 					       errorcodesubcode_hexstr);
 | |
| 			snprintf(errorcodesubcode_str, 255, "%s%s",
 | |
| 				 code_str, subcode_str);
 | |
| 			json_object_string_add(json_peer,
 | |
| 					       "lastNotificationReason",
 | |
| 					       errorcodesubcode_str);
 | |
| 			json_object_boolean_add(json_peer,
 | |
| 						"lastNotificationHardReset",
 | |
| 						peer->notify.hard_reset);
 | |
| 			if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED
 | |
| 			    && peer->notify.code == BGP_NOTIFY_CEASE
 | |
| 			    && (peer->notify.subcode
 | |
| 				== BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN
 | |
| 				|| peer->notify.subcode
 | |
| 				== BGP_NOTIFY_CEASE_ADMIN_RESET)
 | |
| 			    && peer->notify.length) {
 | |
| 				char msgbuf[1024];
 | |
| 				const char *msg_str;
 | |
| 
 | |
| 				msg_str = bgp_notify_admin_message(
 | |
| 					     msgbuf, sizeof(msgbuf),
 | |
| 					     (uint8_t *)peer->notify.data,
 | |
| 					     peer->notify.length);
 | |
| 				if (msg_str)
 | |
| 					json_object_string_add(
 | |
| 					   json_peer,
 | |
| 					   "lastShutdownDescription",
 | |
| 					   msg_str);
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 		json_object_string_add(json_peer, "lastResetDueTo",
 | |
| 				       peer_down_str[(int)peer->last_reset]);
 | |
| 		json_object_int_add(json_peer, "lastResetCode",
 | |
| 				    peer->last_reset);
 | |
| 		json_object_string_add(json_peer, "softwareVersion",
 | |
| 				       peer->soft_version ? peer->soft_version
 | |
| 							  : "n/a");
 | |
| 	} else {
 | |
| 		if (peer->last_reset == PEER_DOWN_NOTIFY_SEND
 | |
| 		    || peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
 | |
| 			code_str = bgp_notify_code_str(peer->notify.code);
 | |
| 			subcode_str =
 | |
| 				bgp_notify_subcode_str(peer->notify.code,
 | |
| 						       peer->notify.subcode);
 | |
| 			vty_out(vty, " Notification %s (%s%s%s)\n",
 | |
| 				peer->last_reset == PEER_DOWN_NOTIFY_SEND
 | |
| 					? "sent"
 | |
| 					: "received",
 | |
| 				code_str, subcode_str,
 | |
| 				peer->notify.hard_reset
 | |
| 					? bgp_notify_subcode_str(
 | |
| 						  BGP_NOTIFY_CEASE,
 | |
| 						  BGP_NOTIFY_CEASE_HARD_RESET)
 | |
| 					: "");
 | |
| 		} else {
 | |
| 			vty_out(vty, "  %s (%s)\n",
 | |
| 				peer_down_str[(int)peer->last_reset],
 | |
| 				peer->soft_version ? peer->soft_version
 | |
| 						   : "n/a");
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static inline bool bgp_has_peer_failed(struct peer *peer, afi_t afi,
 | |
| 				       safi_t safi)
 | |
| {
 | |
| 	return ((!peer_established(peer)) || !peer->afc_recv[afi][safi]);
 | |
| }
 | |
| 
 | |
| static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
 | |
| 				    struct peer *peer, json_object *json_peer,
 | |
| 				    int max_neighbor_width, bool use_json)
 | |
| {
 | |
| 	char timebuf[BGP_UPTIME_LEN], dn_flag[2];
 | |
| 	int len;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		if (peer_dynamic_neighbor(peer))
 | |
| 			json_object_boolean_true_add(json_peer,
 | |
| 						     "dynamicPeer");
 | |
| 		if (peer->hostname)
 | |
| 			json_object_string_add(json_peer, "hostname",
 | |
| 					       peer->hostname);
 | |
| 
 | |
| 		if (peer->domainname)
 | |
| 			json_object_string_add(json_peer, "domainname",
 | |
| 					       peer->domainname);
 | |
| 		json_object_int_add(json_peer, "connectionsEstablished",
 | |
| 				    peer->established);
 | |
| 		json_object_int_add(json_peer, "connectionsDropped",
 | |
| 				    peer->dropped);
 | |
| 		peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
 | |
| 			    use_json, json_peer);
 | |
| 		if (peer_established(peer))
 | |
| 			json_object_string_add(json_peer, "lastResetDueTo",
 | |
| 					       "AFI/SAFI Not Negotiated");
 | |
| 		else
 | |
| 			bgp_show_peer_reset(NULL, peer, json_peer, true);
 | |
| 	} else {
 | |
| 		dn_flag[1] = '\0';
 | |
| 		dn_flag[0] = peer_dynamic_neighbor(peer) ? '*' : '\0';
 | |
| 		if (peer->hostname
 | |
| 		    && CHECK_FLAG(bgp->flags, BGP_FLAG_SHOW_HOSTNAME))
 | |
| 			len = vty_out(vty, "%s%s(%s)", dn_flag,
 | |
| 				      peer->hostname, peer->host);
 | |
| 		else
 | |
| 			len = vty_out(vty, "%s%s", dn_flag, peer->host);
 | |
| 
 | |
| 		/* pad the neighbor column with spaces */
 | |
| 		if (len < max_neighbor_width)
 | |
| 			vty_out(vty, "%*s", max_neighbor_width - len,
 | |
| 				" ");
 | |
| 		vty_out(vty, "%7d %7d %9s", peer->established,
 | |
| 			peer->dropped,
 | |
| 			peer_uptime(peer->uptime, timebuf,
 | |
| 				    BGP_UPTIME_LEN, 0, NULL));
 | |
| 		if (peer_established(peer))
 | |
| 			vty_out(vty, "  AFI/SAFI Not Negotiated\n");
 | |
| 		else
 | |
| 			bgp_show_peer_reset(vty, peer, NULL,
 | |
| 					    false);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Strip peer's description to the given size. */
 | |
| static char *bgp_peer_description_stripped(char *desc, uint32_t size)
 | |
| {
 | |
| 	static char stripped[BUFSIZ];
 | |
| 	uint32_t i = 0;
 | |
| 	uint32_t last_space = size;
 | |
| 
 | |
| 	while (i < size) {
 | |
| 		if (*(desc + i) == '\0') {
 | |
| 			stripped[i] = '\0';
 | |
| 			return stripped;
 | |
| 		}
 | |
| 		if (i != 0 && *(desc + i) == ' ' && last_space != i - 1)
 | |
| 			last_space = i;
 | |
| 		stripped[i] = *(desc + i);
 | |
| 		i++;
 | |
| 	}
 | |
| 
 | |
| 	stripped[last_space] = '\0';
 | |
| 
 | |
| 	return stripped;
 | |
| }
 | |
| 
 | |
| /* Determine whether var peer should be filtered out of the summary. */
 | |
| static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
 | |
| 					      struct peer *fpeer, int as_type,
 | |
| 					      as_t as)
 | |
| {
 | |
| 
 | |
| 	/* filter neighbor XXXX */
 | |
| 	if (fpeer && fpeer != peer)
 | |
| 		return true;
 | |
| 
 | |
| 	/* filter remote-as (internal|external) */
 | |
| 	if (as_type != AS_UNSPECIFIED) {
 | |
| 		if (peer->as_type == AS_SPECIFIED) {
 | |
| 			if (as_type == AS_INTERNAL) {
 | |
| 				if (peer->as != peer->local_as)
 | |
| 					return true;
 | |
| 			} else if (peer->as == peer->local_as)
 | |
| 				return true;
 | |
| 		} else if (as_type != peer->as_type)
 | |
| 			return true;
 | |
| 	} else if (as && as != peer->as) /* filter remote-as XXX */
 | |
| 		return true;
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| /* Show BGP peer's summary information.
 | |
|  *
 | |
|  * Peer's description is stripped according to if `wide` option is given
 | |
|  * or not.
 | |
|  *
 | |
|  * When adding new columns to `show bgp summary` output, please make
 | |
|  * sure `Desc` is the lastest column to show because it can contain
 | |
|  * whitespaces and the whole output will be tricky.
 | |
|  */
 | |
| static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 | |
| 			    struct peer *fpeer, int as_type, as_t as,
 | |
| 			    uint16_t show_flags)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	unsigned int count = 0, dn_count = 0;
 | |
| 	char timebuf[BGP_UPTIME_LEN], dn_flag[2];
 | |
| 	char neighbor_buf[VTY_BUFSIZ];
 | |
| 	int neighbor_col_default_width = 16;
 | |
| 	int len, failed_count = 0;
 | |
| 	unsigned int filtered_count = 0;
 | |
| 	int max_neighbor_width = 0;
 | |
| 	int pfx_rcd_safi;
 | |
| 	json_object *json = NULL;
 | |
| 	json_object *json_peer = NULL;
 | |
| 	json_object *json_peers = NULL;
 | |
| 	struct peer_af *paf;
 | |
| 	struct bgp_filter *filter;
 | |
| 	bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 | |
| 	bool show_failed = CHECK_FLAG(show_flags, BGP_SHOW_OPT_FAILED);
 | |
| 	bool show_established =
 | |
| 		CHECK_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
 | |
| 	bool show_wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 | |
| 	bool show_terse = CHECK_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
 | |
| 
 | |
| 	/* labeled-unicast routes are installed in the unicast table so in order
 | |
| 	 * to
 | |
| 	 * display the correct PfxRcd value we must look at SAFI_UNICAST
 | |
| 	 */
 | |
| 
 | |
| 	if (safi == SAFI_LABELED_UNICAST)
 | |
| 		pfx_rcd_safi = SAFI_UNICAST;
 | |
| 	else
 | |
| 		pfx_rcd_safi = safi;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json = json_object_new_object();
 | |
| 		json_peers = json_object_new_object();
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			if (bgp_show_summary_is_peer_filtered(peer, fpeer,
 | |
| 							      as_type, as)) {
 | |
| 				filtered_count++;
 | |
| 				count++;
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 				continue;
 | |
| 
 | |
| 			if (peer->afc[afi][safi]) {
 | |
| 				/* See if we have at least a single failed peer */
 | |
| 				if (bgp_has_peer_failed(peer, afi, safi))
 | |
| 					failed_count++;
 | |
| 				count++;
 | |
| 			}
 | |
| 			if (peer_dynamic_neighbor(peer))
 | |
| 				dn_count++;
 | |
| 		}
 | |
| 
 | |
| 	} else {
 | |
| 		/* Loop over all neighbors that will be displayed to determine
 | |
| 		 * how many
 | |
| 		 * characters are needed for the Neighbor column
 | |
| 		 */
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			if (bgp_show_summary_is_peer_filtered(peer, fpeer,
 | |
| 							      as_type, as)) {
 | |
| 				filtered_count++;
 | |
| 				count++;
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 				continue;
 | |
| 
 | |
| 			if (peer->afc[afi][safi]) {
 | |
| 				memset(dn_flag, '\0', sizeof(dn_flag));
 | |
| 				if (peer_dynamic_neighbor(peer))
 | |
| 					dn_flag[0] = '*';
 | |
| 
 | |
| 				if (peer->hostname
 | |
| 				    && CHECK_FLAG(bgp->flags,
 | |
| 						  BGP_FLAG_SHOW_HOSTNAME))
 | |
| 					snprintf(neighbor_buf,
 | |
| 						 sizeof(neighbor_buf),
 | |
| 						 "%s%s(%s) ", dn_flag,
 | |
| 						 peer->hostname, peer->host);
 | |
| 				else
 | |
| 					snprintf(neighbor_buf,
 | |
| 						 sizeof(neighbor_buf), "%s%s ",
 | |
| 						 dn_flag, peer->host);
 | |
| 
 | |
| 				len = strlen(neighbor_buf);
 | |
| 
 | |
| 				if (len > max_neighbor_width)
 | |
| 					max_neighbor_width = len;
 | |
| 
 | |
| 				/* See if we have at least a single failed peer */
 | |
| 				if (bgp_has_peer_failed(peer, afi, safi))
 | |
| 					failed_count++;
 | |
| 				count++;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/* Originally we displayed the Neighbor column as 16
 | |
| 		 * characters wide so make that the default
 | |
| 		 */
 | |
| 		if (max_neighbor_width < neighbor_col_default_width)
 | |
| 			max_neighbor_width = neighbor_col_default_width;
 | |
| 	}
 | |
| 
 | |
| 	if (show_failed && !failed_count) {
 | |
| 		if (use_json) {
 | |
| 			json_object_int_add(json, "failedPeersCount", 0);
 | |
| 			json_object_int_add(json, "dynamicPeers", dn_count);
 | |
| 			json_object_int_add(json, "totalPeers", count);
 | |
| 
 | |
| 			vty_json(vty, json);
 | |
| 		} else {
 | |
| 			vty_out(vty, "%% No failed BGP neighbors found\n");
 | |
| 		}
 | |
| 		return CMD_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	count = 0;		/* Reset the value as its used again */
 | |
| 	filtered_count = 0;
 | |
| 	dn_count = 0;
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 		if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 			continue;
 | |
| 
 | |
| 		if (!peer->afc[afi][safi])
 | |
| 			continue;
 | |
| 
 | |
| 		if (!count) {
 | |
| 			unsigned long ents;
 | |
| 			char memstrbuf[MTYPE_MEMSTR_LEN];
 | |
| 			int64_t vrf_id_ui;
 | |
| 
 | |
| 			vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN)
 | |
| 					    ? -1
 | |
| 					    : (int64_t)bgp->vrf_id;
 | |
| 
 | |
| 			/* Usage summary and header */
 | |
| 			if (use_json) {
 | |
| 				json_object_string_addf(json, "routerId",
 | |
| 							"%pI4",
 | |
| 							&bgp->router_id);
 | |
| 				asn_asn2json(json, "as", bgp->as,
 | |
| 					     bgp->asnotation);
 | |
| 				json_object_int_add(json, "vrfId", vrf_id_ui);
 | |
| 				json_object_string_add(
 | |
| 					json, "vrfName",
 | |
| 					(bgp->inst_type
 | |
| 					 == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 						? VRF_DEFAULT_NAME
 | |
| 						: bgp->name);
 | |
| 			} else {
 | |
| 				vty_out(vty,
 | |
| 					"BGP router identifier %pI4, local AS number %s vrf-id %d",
 | |
| 					&bgp->router_id, bgp->as_pretty,
 | |
| 					bgp->vrf_id == VRF_UNKNOWN
 | |
| 						? -1
 | |
| 						: (int)bgp->vrf_id);
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			if (bgp_update_delay_configured(bgp)) {
 | |
| 				if (use_json) {
 | |
| 					json_object_int_add(
 | |
| 						json, "updateDelayLimit",
 | |
| 						bgp->v_update_delay);
 | |
| 
 | |
| 					if (bgp->v_update_delay
 | |
| 					    != bgp->v_establish_wait)
 | |
| 						json_object_int_add(
 | |
| 							json,
 | |
| 							"updateDelayEstablishWait",
 | |
| 							bgp->v_establish_wait);
 | |
| 
 | |
| 					if (bgp_update_delay_active(bgp)) {
 | |
| 						json_object_string_add(
 | |
| 							json,
 | |
| 							"updateDelayFirstNeighbor",
 | |
| 							bgp->update_delay_begin_time);
 | |
| 						json_object_boolean_true_add(
 | |
| 							json,
 | |
| 							"updateDelayInProgress");
 | |
| 					} else {
 | |
| 						if (bgp->update_delay_over) {
 | |
| 							json_object_string_add(
 | |
| 								json,
 | |
| 								"updateDelayFirstNeighbor",
 | |
| 								bgp->update_delay_begin_time);
 | |
| 							json_object_string_add(
 | |
| 								json,
 | |
| 								"updateDelayBestpathResumed",
 | |
| 								bgp->update_delay_end_time);
 | |
| 							json_object_string_add(
 | |
| 								json,
 | |
| 								"updateDelayZebraUpdateResume",
 | |
| 								bgp->update_delay_zebra_resume_time);
 | |
| 							json_object_string_add(
 | |
| 								json,
 | |
| 								"updateDelayPeerUpdateResume",
 | |
| 								bgp->update_delay_peers_resume_time);
 | |
| 						}
 | |
| 					}
 | |
| 				} else {
 | |
| 					vty_out(vty,
 | |
| 						"Read-only mode update-delay limit: %d seconds\n",
 | |
| 						bgp->v_update_delay);
 | |
| 					if (bgp->v_update_delay
 | |
| 					    != bgp->v_establish_wait)
 | |
| 						vty_out(vty,
 | |
| 							"                   Establish wait: %d seconds\n",
 | |
| 							bgp->v_establish_wait);
 | |
| 
 | |
| 					if (bgp_update_delay_active(bgp)) {
 | |
| 						vty_out(vty,
 | |
| 							"  First neighbor established: %s\n",
 | |
| 							bgp->update_delay_begin_time);
 | |
| 						vty_out(vty,
 | |
| 							"  Delay in progress\n");
 | |
| 					} else {
 | |
| 						if (bgp->update_delay_over) {
 | |
| 							vty_out(vty,
 | |
| 								"  First neighbor established: %s\n",
 | |
| 								bgp->update_delay_begin_time);
 | |
| 							vty_out(vty,
 | |
| 								"          Best-paths resumed: %s\n",
 | |
| 								bgp->update_delay_end_time);
 | |
| 							vty_out(vty,
 | |
| 								"        zebra update resumed: %s\n",
 | |
| 								bgp->update_delay_zebra_resume_time);
 | |
| 							vty_out(vty,
 | |
| 								"        peers update resumed: %s\n",
 | |
| 								bgp->update_delay_peers_resume_time);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (use_json) {
 | |
| 				if (bgp_maxmed_onstartup_configured(bgp)
 | |
| 				    && bgp->maxmed_active)
 | |
| 					json_object_boolean_true_add(
 | |
| 						json, "maxMedOnStartup");
 | |
| 				if (bgp->v_maxmed_admin)
 | |
| 					json_object_boolean_true_add(
 | |
| 						json, "maxMedAdministrative");
 | |
| 
 | |
| 				json_object_int_add(
 | |
| 					json, "tableVersion",
 | |
| 					bgp_table_version(bgp->rib[afi][safi]));
 | |
| 
 | |
| 				ents = bgp_table_count(bgp->rib[afi][safi]);
 | |
| 				json_object_int_add(json, "ribCount", ents);
 | |
| 				json_object_int_add(
 | |
| 					json, "ribMemory",
 | |
| 					ents * sizeof(struct bgp_dest));
 | |
| 
 | |
| 				ents = bgp->af_peer_count[afi][safi];
 | |
| 				json_object_int_add(json, "peerCount", ents);
 | |
| 				json_object_int_add(json, "peerMemory",
 | |
| 						    ents * sizeof(struct peer));
 | |
| 
 | |
| 				if ((ents = listcount(bgp->group))) {
 | |
| 					json_object_int_add(
 | |
| 						json, "peerGroupCount", ents);
 | |
| 					json_object_int_add(
 | |
| 						json, "peerGroupMemory",
 | |
| 						ents * sizeof(struct
 | |
| 							      peer_group));
 | |
| 				}
 | |
| 
 | |
| 				if (CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 					       BGP_CONFIG_DAMPENING))
 | |
| 					json_object_boolean_true_add(
 | |
| 						json, "dampeningEnabled");
 | |
| 			} else {
 | |
| 				if (!show_terse) {
 | |
| 					if (bgp_maxmed_onstartup_configured(bgp)
 | |
| 					    && bgp->maxmed_active)
 | |
| 						vty_out(vty,
 | |
| 							"Max-med on-startup active\n");
 | |
| 					if (bgp->v_maxmed_admin)
 | |
| 						vty_out(vty,
 | |
| 							"Max-med administrative active\n");
 | |
| 
 | |
| 					vty_out(vty,
 | |
| 						"BGP table version %" PRIu64
 | |
| 						"\n",
 | |
| 						bgp_table_version(
 | |
| 							bgp->rib[afi][safi]));
 | |
| 
 | |
| 					ents = bgp_table_count(
 | |
| 						bgp->rib[afi][safi]);
 | |
| 					vty_out(vty,
 | |
| 						"RIB entries %ld, using %s of memory\n",
 | |
| 						ents,
 | |
| 						mtype_memstr(
 | |
| 							memstrbuf,
 | |
| 							sizeof(memstrbuf),
 | |
| 							ents
 | |
| 								* sizeof(
 | |
| 									struct
 | |
| 									bgp_dest)));
 | |
| 
 | |
| 					/* Peer related usage */
 | |
| 					ents = bgp->af_peer_count[afi][safi];
 | |
| 					vty_out(vty,
 | |
| 						"Peers %ld, using %s of memory\n",
 | |
| 						ents,
 | |
| 						mtype_memstr(
 | |
| 							memstrbuf,
 | |
| 							sizeof(memstrbuf),
 | |
| 							ents
 | |
| 								* sizeof(
 | |
| 									struct
 | |
| 									peer)));
 | |
| 
 | |
| 					if ((ents = listcount(bgp->group)))
 | |
| 						vty_out(vty,
 | |
| 							"Peer groups %ld, using %s of memory\n",
 | |
| 							ents,
 | |
| 							mtype_memstr(
 | |
| 								memstrbuf,
 | |
| 								sizeof(memstrbuf),
 | |
| 								ents
 | |
| 									* sizeof(
 | |
| 										struct
 | |
| 										peer_group)));
 | |
| 
 | |
| 					if (CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 						       BGP_CONFIG_DAMPENING))
 | |
| 						vty_out(vty,
 | |
| 							"Dampening enabled.\n");
 | |
| 				}
 | |
| 				if (show_failed) {
 | |
| 					vty_out(vty, "\n");
 | |
| 
 | |
| 					/* Subtract 8 here because 'Neighbor' is
 | |
| 					 * 8 characters */
 | |
| 					vty_out(vty, "Neighbor");
 | |
| 					vty_out(vty, "%*s",
 | |
| 						max_neighbor_width - 8, " ");
 | |
| 					vty_out(vty,
 | |
| 						BGP_SHOW_SUMMARY_HEADER_FAILED);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		paf = peer_af_find(peer, afi, safi);
 | |
| 		filter = &peer->filter[afi][safi];
 | |
| 
 | |
| 		count++;
 | |
| 		/* Works for both failed & successful cases */
 | |
| 		if (peer_dynamic_neighbor(peer))
 | |
| 			dn_count++;
 | |
| 
 | |
| 		if (use_json) {
 | |
| 			json_peer = NULL;
 | |
| 			if (bgp_show_summary_is_peer_filtered(peer, fpeer,
 | |
| 							      as_type, as)) {
 | |
| 				filtered_count++;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (show_failed &&
 | |
| 			    bgp_has_peer_failed(peer, afi, safi)) {
 | |
| 				json_peer = json_object_new_object();
 | |
| 				bgp_show_failed_summary(vty, bgp, peer,
 | |
| 							json_peer, 0, use_json);
 | |
| 			} else if (!show_failed) {
 | |
| 				if (show_established
 | |
| 				    && bgp_has_peer_failed(peer, afi, safi)) {
 | |
| 					filtered_count++;
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				json_peer = json_object_new_object();
 | |
| 				if (peer_dynamic_neighbor(peer)) {
 | |
| 					json_object_boolean_true_add(json_peer,
 | |
| 								     "dynamicPeer");
 | |
| 				}
 | |
| 
 | |
| 				if (peer->hostname)
 | |
| 					json_object_string_add(json_peer, "hostname",
 | |
| 							       peer->hostname);
 | |
| 
 | |
| 				if (peer->domainname)
 | |
| 					json_object_string_add(json_peer, "domainname",
 | |
| 							       peer->domainname);
 | |
| 
 | |
| 				asn_asn2json(json_peer, "remoteAs", peer->as,
 | |
| 					     bgp->asnotation);
 | |
| 				asn_asn2json(json_peer, "localAs",
 | |
| 					     peer->change_local_as
 | |
| 						     ? peer->change_local_as
 | |
| 						     : peer->local_as,
 | |
| 					     bgp->asnotation);
 | |
| 				json_object_int_add(json_peer, "version", 4);
 | |
| 				json_object_int_add(json_peer, "msgRcvd",
 | |
| 						    PEER_TOTAL_RX(peer));
 | |
| 				json_object_int_add(json_peer, "msgSent",
 | |
| 						    PEER_TOTAL_TX(peer));
 | |
| 
 | |
| 				atomic_size_t outq_count, inq_count;
 | |
| 				outq_count = atomic_load_explicit(
 | |
| 					&peer->obuf->count,
 | |
| 					memory_order_relaxed);
 | |
| 				inq_count = atomic_load_explicit(
 | |
| 					&peer->ibuf->count,
 | |
| 					memory_order_relaxed);
 | |
| 
 | |
| 				json_object_int_add(
 | |
| 					json_peer, "tableVersion",
 | |
| 					(paf && PAF_SUBGRP(paf))
 | |
| 						? paf->subgroup->version
 | |
| 						: 0);
 | |
| 				json_object_int_add(json_peer, "outq",
 | |
| 						    outq_count);
 | |
| 				json_object_int_add(json_peer, "inq",
 | |
| 						    inq_count);
 | |
| 				peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
 | |
| 					    use_json, json_peer);
 | |
| 
 | |
| 				json_object_int_add(json_peer, "pfxRcd",
 | |
| 						    peer->pcount[afi][pfx_rcd_safi]);
 | |
| 
 | |
| 				if (paf && PAF_SUBGRP(paf))
 | |
| 					json_object_int_add(
 | |
| 						json_peer, "pfxSnt",
 | |
| 						(PAF_SUBGRP(paf))->scount);
 | |
| 				else
 | |
| 					json_object_int_add(json_peer, "pfxSnt",
 | |
| 							    0);
 | |
| 
 | |
| 				/* BGP FSM state */
 | |
| 				if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
 | |
| 				    || CHECK_FLAG(peer->bgp->flags,
 | |
| 						  BGP_FLAG_SHUTDOWN))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "state",
 | |
| 							       "Idle (Admin)");
 | |
| 				else if (peer->afc_recv[afi][safi])
 | |
| 					json_object_string_add(
 | |
| 						json_peer, "state",
 | |
| 						lookup_msg(bgp_status_msg,
 | |
| 							   peer->status, NULL));
 | |
| 				else if (CHECK_FLAG(
 | |
| 						 peer->sflags,
 | |
| 						 PEER_STATUS_PREFIX_OVERFLOW))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "state",
 | |
| 							       "Idle (PfxCt)");
 | |
| 				else
 | |
| 					json_object_string_add(
 | |
| 						json_peer, "state",
 | |
| 						lookup_msg(bgp_status_msg,
 | |
| 							   peer->status, NULL));
 | |
| 
 | |
| 				/* BGP peer state */
 | |
| 				if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
 | |
| 				    || CHECK_FLAG(peer->bgp->flags,
 | |
| 						  BGP_FLAG_SHUTDOWN))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "peerState",
 | |
| 							       "Admin");
 | |
| 				else if (CHECK_FLAG(
 | |
| 						 peer->sflags,
 | |
| 						 PEER_STATUS_PREFIX_OVERFLOW))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "peerState",
 | |
| 							       "PfxCt");
 | |
| 				else if (CHECK_FLAG(peer->flags,
 | |
| 						    PEER_FLAG_PASSIVE))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "peerState",
 | |
| 							       "Passive");
 | |
| 				else if (CHECK_FLAG(peer->sflags,
 | |
| 						    PEER_STATUS_NSF_WAIT))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "peerState",
 | |
| 							       "NSF passive");
 | |
| 				else if (CHECK_FLAG(
 | |
| 						 peer->bgp->flags,
 | |
| 						 BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 					 && (!bgp_inbound_policy_exists(peer,
 | |
| 									filter)
 | |
| 					     || !bgp_outbound_policy_exists(
 | |
| 						     peer, filter)))
 | |
| 					json_object_string_add(json_peer,
 | |
| 							       "peerState",
 | |
| 							       "Policy");
 | |
| 				else
 | |
| 					json_object_string_add(
 | |
| 						json_peer, "peerState", "OK");
 | |
| 
 | |
| 				json_object_int_add(json_peer, "connectionsEstablished",
 | |
| 						    peer->established);
 | |
| 				json_object_int_add(json_peer, "connectionsDropped",
 | |
| 						    peer->dropped);
 | |
| 				if (peer->desc)
 | |
| 					json_object_string_add(
 | |
| 						json_peer, "desc", peer->desc);
 | |
| 			}
 | |
| 			/* Avoid creating empty peer dicts in JSON */
 | |
| 			if (json_peer == NULL)
 | |
| 				continue;
 | |
| 
 | |
| 			if (peer->conf_if)
 | |
| 				json_object_string_add(json_peer, "idType",
 | |
| 						       "interface");
 | |
| 			else if (peer->su.sa.sa_family == AF_INET)
 | |
| 				json_object_string_add(json_peer, "idType",
 | |
| 						       "ipv4");
 | |
| 			else if (peer->su.sa.sa_family == AF_INET6)
 | |
| 				json_object_string_add(json_peer, "idType",
 | |
| 						       "ipv6");
 | |
| 			json_object_object_add(json_peers, peer->host,
 | |
| 					       json_peer);
 | |
| 		} else {
 | |
| 			if (bgp_show_summary_is_peer_filtered(peer, fpeer,
 | |
| 							      as_type, as)) {
 | |
| 				filtered_count++;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (show_failed &&
 | |
| 			    bgp_has_peer_failed(peer, afi, safi)) {
 | |
| 				bgp_show_failed_summary(vty, bgp, peer, NULL,
 | |
| 							max_neighbor_width,
 | |
| 							use_json);
 | |
| 			} else if (!show_failed) {
 | |
| 				if (show_established
 | |
| 				    && bgp_has_peer_failed(peer, afi, safi)) {
 | |
| 					filtered_count++;
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				if ((count - filtered_count) == 1) {
 | |
| 					/* display headline before the first
 | |
| 					 * neighbor line */
 | |
| 					vty_out(vty, "\n");
 | |
| 
 | |
| 					/* Subtract 8 here because 'Neighbor' is
 | |
| 					 * 8 characters */
 | |
| 					vty_out(vty, "Neighbor");
 | |
| 					vty_out(vty, "%*s",
 | |
| 						max_neighbor_width - 8, " ");
 | |
| 					vty_out(vty,
 | |
| 						show_wide
 | |
| 							? BGP_SHOW_SUMMARY_HEADER_ALL_WIDE
 | |
| 							: BGP_SHOW_SUMMARY_HEADER_ALL);
 | |
| 				}
 | |
| 
 | |
| 				memset(dn_flag, '\0', sizeof(dn_flag));
 | |
| 				if (peer_dynamic_neighbor(peer)) {
 | |
| 					dn_flag[0] = '*';
 | |
| 				}
 | |
| 
 | |
| 				if (peer->hostname
 | |
| 				    && CHECK_FLAG(bgp->flags,
 | |
| 						  BGP_FLAG_SHOW_HOSTNAME))
 | |
| 					len = vty_out(vty, "%s%s(%s)", dn_flag,
 | |
| 						      peer->hostname,
 | |
| 						      peer->host);
 | |
| 				else
 | |
| 					len = vty_out(vty, "%s%s", dn_flag, peer->host);
 | |
| 
 | |
| 				/* pad the neighbor column with spaces */
 | |
| 				if (len < max_neighbor_width)
 | |
| 					vty_out(vty, "%*s", max_neighbor_width - len,
 | |
| 						" ");
 | |
| 
 | |
| 				atomic_size_t outq_count, inq_count;
 | |
| 				outq_count = atomic_load_explicit(
 | |
| 					&peer->obuf->count,
 | |
| 					memory_order_relaxed);
 | |
| 				inq_count = atomic_load_explicit(
 | |
| 					&peer->ibuf->count,
 | |
| 					memory_order_relaxed);
 | |
| 
 | |
| 				vty_out(vty, "4 ");
 | |
| 				vty_out(vty, ASN_FORMAT_SPACE(bgp->asnotation),
 | |
| 					&peer->as);
 | |
| 				if (show_wide)
 | |
| 					vty_out(vty,
 | |
| 						ASN_FORMAT_SPACE(
 | |
| 							bgp->asnotation),
 | |
| 						peer->change_local_as
 | |
| 							? &peer->change_local_as
 | |
| 							: &peer->local_as);
 | |
| 				vty_out(vty,
 | |
| 					" %9u %9u %8" PRIu64 " %4zu %4zu %8s",
 | |
| 					PEER_TOTAL_RX(peer),
 | |
| 					PEER_TOTAL_TX(peer),
 | |
| 					(paf && PAF_SUBGRP(paf))
 | |
| 						? paf->subgroup->version
 | |
| 						: 0,
 | |
| 					inq_count, outq_count,
 | |
| 					peer_uptime(peer->uptime, timebuf,
 | |
| 						    BGP_UPTIME_LEN, 0, NULL));
 | |
| 
 | |
| 				if (peer_established(peer)) {
 | |
| 					if (peer->afc_recv[afi][safi]) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    bgp->flags,
 | |
| 							    BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 						    && !bgp_inbound_policy_exists(
 | |
| 							    peer, filter))
 | |
| 							vty_out(vty, " %12s",
 | |
| 								"(Policy)");
 | |
| 						else
 | |
| 							vty_out(vty,
 | |
| 								" %12u",
 | |
| 								peer->pcount
 | |
| 									[afi]
 | |
| 									[pfx_rcd_safi]);
 | |
| 					} else {
 | |
| 						vty_out(vty, "        NoNeg");
 | |
| 					}
 | |
| 
 | |
| 					if (paf && PAF_SUBGRP(paf)) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    bgp->flags,
 | |
| 							    BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 						    && !bgp_outbound_policy_exists(
 | |
| 							    peer, filter))
 | |
| 							vty_out(vty, " %8s",
 | |
| 								"(Policy)");
 | |
| 						else
 | |
| 							vty_out(vty,
 | |
| 								" %8u",
 | |
| 								(PAF_SUBGRP(
 | |
| 									 paf))
 | |
| 									->scount);
 | |
| 					} else {
 | |
| 						vty_out(vty, "    NoNeg");
 | |
| 					}
 | |
| 				} else {
 | |
| 					if (CHECK_FLAG(peer->flags,
 | |
| 						       PEER_FLAG_SHUTDOWN)
 | |
| 					    || CHECK_FLAG(peer->bgp->flags,
 | |
| 							  BGP_FLAG_SHUTDOWN))
 | |
| 						vty_out(vty, " Idle (Admin)");
 | |
| 					else if (CHECK_FLAG(
 | |
| 							    peer->sflags,
 | |
| 							    PEER_STATUS_PREFIX_OVERFLOW))
 | |
| 						vty_out(vty, " Idle (PfxCt)");
 | |
| 					else
 | |
| 						vty_out(vty, " %12s",
 | |
| 							lookup_msg(bgp_status_msg,
 | |
| 								   peer->status, NULL));
 | |
| 
 | |
| 					vty_out(vty, " %8u", 0);
 | |
| 				}
 | |
| 				/* Make sure `Desc` column is the lastest in
 | |
| 				 * the output.
 | |
| 				 */
 | |
| 				if (peer->desc)
 | |
| 					vty_out(vty, " %s",
 | |
| 						bgp_peer_description_stripped(
 | |
| 							peer->desc,
 | |
| 							show_wide ? 64 : 20));
 | |
| 				else
 | |
| 					vty_out(vty, " N/A");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_object_object_add(json, "peers", json_peers);
 | |
| 		json_object_int_add(json, "failedPeers", failed_count);
 | |
| 		json_object_int_add(json, "displayedPeers",
 | |
| 				    count - filtered_count);
 | |
| 		json_object_int_add(json, "totalPeers", count);
 | |
| 		json_object_int_add(json, "dynamicPeers", dn_count);
 | |
| 
 | |
| 		if (!show_failed)
 | |
| 			bgp_show_bestpath_json(bgp, json);
 | |
| 
 | |
| 		vty_json(vty, json);
 | |
| 	} else {
 | |
| 		if (count) {
 | |
| 			if (filtered_count == count)
 | |
| 				vty_out(vty, "\n%% No matching neighbor\n");
 | |
| 			else {
 | |
| 				if (show_failed)
 | |
| 					vty_out(vty, "\nDisplayed neighbors %d",
 | |
| 						failed_count);
 | |
| 				else if (as_type != AS_UNSPECIFIED || as
 | |
| 					 || fpeer || show_established)
 | |
| 					vty_out(vty, "\nDisplayed neighbors %d",
 | |
| 						count - filtered_count);
 | |
| 
 | |
| 				vty_out(vty, "\nTotal number of neighbors %d\n",
 | |
| 					count);
 | |
| 			}
 | |
| 		} else {
 | |
| 			vty_out(vty, "No %s neighbor is configured\n",
 | |
| 				get_afi_safi_str(afi, safi, false));
 | |
| 		}
 | |
| 
 | |
| 		if (dn_count) {
 | |
| 			vty_out(vty, "* - dynamic neighbor\n");
 | |
| 			vty_out(vty, "%d dynamic neighbor(s), limit %d\n",
 | |
| 				dn_count, bgp->dynamic_neighbors_limit);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
 | |
| 				      int safi, struct peer *fpeer, int as_type,
 | |
| 				      as_t as, uint16_t show_flags)
 | |
| {
 | |
| 	int is_first = 1;
 | |
| 	int afi_wildcard = (afi == AFI_MAX);
 | |
| 	int safi_wildcard = (safi == SAFI_MAX);
 | |
| 	int is_wildcard = (afi_wildcard || safi_wildcard);
 | |
| 	bool nbr_output = false;
 | |
| 	bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 | |
| 
 | |
| 	if (use_json && is_wildcard)
 | |
| 		vty_out(vty, "{\n");
 | |
| 	if (afi_wildcard)
 | |
| 		afi = 1; /* AFI_IP */
 | |
| 	while (afi < AFI_MAX) {
 | |
| 		if (safi_wildcard)
 | |
| 			safi = 1; /* SAFI_UNICAST */
 | |
| 		while (safi < SAFI_MAX) {
 | |
| 			if (bgp_afi_safi_peer_exists(bgp, afi, safi)) {
 | |
| 				nbr_output = true;
 | |
| 
 | |
| 				if (is_wildcard) {
 | |
| 					/*
 | |
| 					 * So limit output to those afi/safi
 | |
| 					 * pairs that
 | |
| 					 * actualy have something interesting in
 | |
| 					 * them
 | |
| 					 */
 | |
| 					if (use_json) {
 | |
| 						if (!is_first)
 | |
| 							vty_out(vty, ",\n");
 | |
| 						else
 | |
| 							is_first = 0;
 | |
| 
 | |
| 						vty_out(vty, "\"%s\":",
 | |
| 							get_afi_safi_str(afi,
 | |
| 									 safi,
 | |
| 									 true));
 | |
| 					} else {
 | |
| 						vty_out(vty,
 | |
| 							"\n%s Summary (%s):\n",
 | |
| 							get_afi_safi_str(afi,
 | |
| 									 safi,
 | |
| 									 false),
 | |
| 							bgp->name_pretty);
 | |
| 					}
 | |
| 				}
 | |
| 				bgp_show_summary(vty, bgp, afi, safi, fpeer,
 | |
| 						 as_type, as, show_flags);
 | |
| 			}
 | |
| 			safi++;
 | |
| 			if (!safi_wildcard)
 | |
| 				safi = SAFI_MAX;
 | |
| 		}
 | |
| 		afi++;
 | |
| 		if (!afi_wildcard)
 | |
| 			afi = AFI_MAX;
 | |
| 	}
 | |
| 
 | |
| 	if (use_json && is_wildcard)
 | |
| 		vty_out(vty, "}\n");
 | |
| 	else if (!nbr_output) {
 | |
| 		if (use_json)
 | |
| 			vty_out(vty, "{}\n");
 | |
| 		else
 | |
| 			vty_out(vty, "%% No BGP neighbors found in %s\n",
 | |
| 				bgp->name_pretty);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
 | |
| 					       safi_t safi,
 | |
| 					       const char *neighbor,
 | |
| 					       int as_type, as_t as,
 | |
| 					       uint16_t show_flags)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 	struct peer *fpeer = NULL;
 | |
| 	int is_first = 1;
 | |
| 	bool nbr_output = false;
 | |
| 	bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 | |
| 
 | |
| 	if (use_json)
 | |
| 		vty_out(vty, "{\n");
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		nbr_output = true;
 | |
| 		if (use_json) {
 | |
| 			if (!is_first)
 | |
| 				vty_out(vty, ",\n");
 | |
| 			else
 | |
| 				is_first = 0;
 | |
| 
 | |
| 			vty_out(vty, "\"%s\":",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 					? VRF_DEFAULT_NAME
 | |
| 					: bgp->name);
 | |
| 		}
 | |
| 		if (neighbor) {
 | |
| 			fpeer = peer_lookup_in_view(vty, bgp, neighbor,
 | |
| 						    use_json);
 | |
| 			if (!fpeer)
 | |
| 				continue;
 | |
| 		}
 | |
| 		bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer, as_type,
 | |
| 					  as, show_flags);
 | |
| 	}
 | |
| 
 | |
| 	if (use_json)
 | |
| 		vty_out(vty, "}\n");
 | |
| 	else if (!nbr_output)
 | |
| 		vty_out(vty, "%% BGP instance not found\n");
 | |
| }
 | |
| 
 | |
| int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
 | |
| 			 safi_t safi, const char *neighbor, int as_type,
 | |
| 			 as_t as, uint16_t show_flags)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 | |
| 	struct peer *fpeer = NULL;
 | |
| 
 | |
| 	if (name) {
 | |
| 		if (strmatch(name, "all")) {
 | |
| 			bgp_show_all_instances_summary_vty(vty, afi, safi,
 | |
| 							   neighbor, as_type,
 | |
| 							   as, show_flags);
 | |
| 			return CMD_SUCCESS;
 | |
| 		} else {
 | |
| 			bgp = bgp_lookup_by_name(name);
 | |
| 
 | |
| 			if (!bgp) {
 | |
| 				if (use_json)
 | |
| 					vty_out(vty, "{}\n");
 | |
| 				else
 | |
| 					vty_out(vty,
 | |
| 						"%% BGP instance not found\n");
 | |
| 				return CMD_WARNING;
 | |
| 			}
 | |
| 
 | |
| 			if (neighbor) {
 | |
| 				fpeer = peer_lookup_in_view(vty, bgp, neighbor,
 | |
| 							    use_json);
 | |
| 				if (!fpeer)
 | |
| 					return CMD_WARNING;
 | |
| 			}
 | |
| 			bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer,
 | |
| 						  as_type, as, show_flags);
 | |
| 			return CMD_SUCCESS;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 
 | |
| 	if (bgp) {
 | |
| 		if (neighbor) {
 | |
| 			fpeer = peer_lookup_in_view(vty, bgp, neighbor,
 | |
| 						    use_json);
 | |
| 			if (!fpeer)
 | |
| 				return CMD_WARNING;
 | |
| 		}
 | |
| 		bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer, as_type,
 | |
| 					  as, show_flags);
 | |
| 	} else {
 | |
| 		if (use_json)
 | |
| 			vty_out(vty, "{}\n");
 | |
| 		else
 | |
| 			vty_out(vty, "%% BGP instance not found\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* `show [ip] bgp summary' commands. */
 | |
| DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
 | |
|       "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
 | |
|       " [" BGP_SAFI_WITH_LABEL_CMD_STR
 | |
|       "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <ASNUM|internal|external>>] [terse] [wide] [json$uj]",
 | |
|       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
 | |
| 	      BGP_SAFI_WITH_LABEL_HELP_STR
 | |
|       "Display the entries for all address families\n"
 | |
|       "Summary of BGP neighbor status\n"
 | |
|       "Show only sessions in Established state\n"
 | |
|       "Show only sessions not in Established state\n"
 | |
|       "Show only the specified neighbor session\n"
 | |
|       "Neighbor to display information about\n"
 | |
|       "Neighbor to display information about\n"
 | |
|       "Neighbor on BGP configured interface\n"
 | |
|       "Show only the specified remote AS sessions\n" AS_STR
 | |
|       "Internal (iBGP) AS sessions\n"
 | |
|       "External (eBGP) AS sessions\n"
 | |
|       "Shorten the information on BGP instances\n"
 | |
|       "Increase table width for longer output\n" JSON_STR)
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	afi_t afi = AFI_MAX;
 | |
| 	safi_t safi = SAFI_MAX;
 | |
| 	as_t as = 0; /* 0 means AS filter not set */
 | |
| 	int as_type = AS_UNSPECIFIED;
 | |
| 	uint16_t show_flags = 0;
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	/* show [ip] bgp */
 | |
| 	if (!all && argv_find(argv, argc, "ip", &idx))
 | |
| 		afi = AFI_IP;
 | |
| 	/* [<vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx))
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 	/* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */
 | |
| 	if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
 | |
| 		argv_find_and_parse_safi(argv, argc, &idx, &safi);
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find(argv, argc, "failed", &idx))
 | |
| 		SET_FLAG(show_flags, BGP_SHOW_OPT_FAILED);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "established", &idx))
 | |
| 		SET_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "remote-as", &idx)) {
 | |
| 		if (argv[idx + 1]->arg[0] == 'i')
 | |
| 			as_type = AS_INTERNAL;
 | |
| 		else if (argv[idx + 1]->arg[0] == 'e')
 | |
| 			as_type = AS_EXTERNAL;
 | |
| 		else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
 | |
| 			vty_out(vty,
 | |
| 				"%% Invalid neighbor remote-as value: %s\n",
 | |
| 				argv[idx + 1]->arg);
 | |
| 			return CMD_SUCCESS;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find(argv, argc, "terse", &idx))
 | |
| 		SET_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "wide", &idx))
 | |
| 		SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 | |
| 
 | |
| 	if (argv_find(argv, argc, "json", &idx))
 | |
| 		SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
 | |
| 
 | |
| 	return bgp_show_summary_vty(vty, vrf, afi, safi, neighbor, as_type, as,
 | |
| 				    show_flags);
 | |
| }
 | |
| 
 | |
| const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json)
 | |
| {
 | |
| 	if (for_json)
 | |
| 		return get_afi_safi_json_str(afi, safi);
 | |
| 	else
 | |
| 		return get_afi_safi_vty_str(afi, safi);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
 | |
| 				      afi_t afi, safi_t safi,
 | |
| 				      uint16_t adv_smcap, uint16_t adv_rmcap,
 | |
| 				      uint16_t rcv_smcap, uint16_t rcv_rmcap,
 | |
| 				      bool use_json, json_object *json_pref)
 | |
| {
 | |
| 	/* Send-Mode */
 | |
| 	if (CHECK_FLAG(p->af_cap[afi][safi], adv_smcap)
 | |
| 	    || CHECK_FLAG(p->af_cap[afi][safi], rcv_smcap)) {
 | |
| 		if (use_json) {
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], adv_smcap)
 | |
| 			    && CHECK_FLAG(p->af_cap[afi][safi], rcv_smcap))
 | |
| 				json_object_string_add(json_pref, "sendMode",
 | |
| 						       "advertisedAndReceived");
 | |
| 			else if (CHECK_FLAG(p->af_cap[afi][safi], adv_smcap))
 | |
| 				json_object_string_add(json_pref, "sendMode",
 | |
| 						       "advertised");
 | |
| 			else if (CHECK_FLAG(p->af_cap[afi][safi], rcv_smcap))
 | |
| 				json_object_string_add(json_pref, "sendMode",
 | |
| 						       "received");
 | |
| 		} else {
 | |
| 			vty_out(vty, "      Send-mode: ");
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], adv_smcap))
 | |
| 				vty_out(vty, "advertised");
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], rcv_smcap))
 | |
| 				vty_out(vty, "%sreceived",
 | |
| 					CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 						   adv_smcap)
 | |
| 						? ", "
 | |
| 						: "");
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Receive-Mode */
 | |
| 	if (CHECK_FLAG(p->af_cap[afi][safi], adv_rmcap)
 | |
| 	    || CHECK_FLAG(p->af_cap[afi][safi], rcv_rmcap)) {
 | |
| 		if (use_json) {
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], adv_rmcap)
 | |
| 			    && CHECK_FLAG(p->af_cap[afi][safi], rcv_rmcap))
 | |
| 				json_object_string_add(json_pref, "recvMode",
 | |
| 						       "advertisedAndReceived");
 | |
| 			else if (CHECK_FLAG(p->af_cap[afi][safi], adv_rmcap))
 | |
| 				json_object_string_add(json_pref, "recvMode",
 | |
| 						       "advertised");
 | |
| 			else if (CHECK_FLAG(p->af_cap[afi][safi], rcv_rmcap))
 | |
| 				json_object_string_add(json_pref, "recvMode",
 | |
| 						       "received");
 | |
| 		} else {
 | |
| 			vty_out(vty, "      Receive-mode: ");
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], adv_rmcap))
 | |
| 				vty_out(vty, "advertised");
 | |
| 			if (CHECK_FLAG(p->af_cap[afi][safi], rcv_rmcap))
 | |
| 				vty_out(vty, "%sreceived",
 | |
| 					CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 						   adv_rmcap)
 | |
| 						? ", "
 | |
| 						: "");
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty,
 | |
| 						     struct peer *p,
 | |
| 						     json_object *json)
 | |
| {
 | |
| 	bool rbit = false;
 | |
| 	bool nbit = false;
 | |
| 
 | |
| 	if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)
 | |
| 	    && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
 | |
| 	    && (peer_established(p))) {
 | |
| 		rbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV);
 | |
| 		nbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV);
 | |
| 	}
 | |
| 
 | |
| 	if (json) {
 | |
| 		json_object_boolean_add(json, "rBit", rbit);
 | |
| 		json_object_boolean_add(json, "nBit", nbit);
 | |
| 	} else {
 | |
| 		vty_out(vty, "\n    R bit: %s", rbit ? "True" : "False");
 | |
| 		vty_out(vty, "\n    N bit: %s\n", nbit ? "True" : "False");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
 | |
| 							   struct peer *peer,
 | |
| 							   json_object *json)
 | |
| {
 | |
| 	const char *mode = "NotApplicable";
 | |
| 
 | |
| 	if (!json)
 | |
| 		vty_out(vty, "\n    Remote GR Mode: ");
 | |
| 
 | |
| 	if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
 | |
| 	    && (peer_established(peer))) {
 | |
| 
 | |
| 		if ((peer->nsf_af_count == 0)
 | |
| 		    && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 
 | |
| 			mode = "Disable";
 | |
| 
 | |
| 		} else if (peer->nsf_af_count == 0
 | |
| 			   && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 
 | |
| 			mode = "Helper";
 | |
| 
 | |
| 		} else if (peer->nsf_af_count != 0
 | |
| 			   && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 
 | |
| 			mode = "Restart";
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (json)
 | |
| 		json_object_string_add(json, "remoteGrMode", mode);
 | |
| 	else
 | |
| 		vty_out(vty, "%s\n", mode);
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
 | |
| 							  struct peer *p,
 | |
| 							  json_object *json)
 | |
| {
 | |
| 	const char *mode = "Invalid";
 | |
| 
 | |
| 	if (!json)
 | |
| 		vty_out(vty, "    Local GR Mode: ");
 | |
| 
 | |
| 	if (bgp_peer_gr_mode_get(p) == PEER_HELPER)
 | |
| 		mode = "Helper";
 | |
| 	else if (bgp_peer_gr_mode_get(p) == PEER_GR)
 | |
| 		mode = "Restart";
 | |
| 	else if (bgp_peer_gr_mode_get(p) == PEER_DISABLE)
 | |
| 		mode = "Disable";
 | |
| 	else if (bgp_peer_gr_mode_get(p) == PEER_GLOBAL_INHERIT) {
 | |
| 		if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_HELPER)
 | |
| 			mode = "Helper*";
 | |
| 		else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_GR)
 | |
| 			mode = "Restart*";
 | |
| 		else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_DISABLE)
 | |
| 			mode = "Disable*";
 | |
| 		else
 | |
| 			mode = "Invalid*";
 | |
| 	}
 | |
| 
 | |
| 	if (json)
 | |
| 		json_object_string_add(json, "localGrMode", mode);
 | |
| 	else
 | |
| 		vty_out(vty, "%s\n", mode);
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
 | |
| 	struct vty *vty, struct peer *peer, json_object *json)
 | |
| {
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	json_object *json_afi_safi = NULL;
 | |
| 	json_object *json_timer = NULL;
 | |
| 	json_object *json_endofrib_status = NULL;
 | |
| 	bool eor_flag = false;
 | |
| 
 | |
| 	FOREACH_AFI_SAFI_NSF (afi, safi) {
 | |
| 		if (!peer->afc[afi][safi])
 | |
| 			continue;
 | |
| 
 | |
| 		if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) ||
 | |
| 		    !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
 | |
| 			continue;
 | |
| 
 | |
| 		if (json) {
 | |
| 			json_afi_safi = json_object_new_object();
 | |
| 			json_endofrib_status = json_object_new_object();
 | |
| 			json_timer = json_object_new_object();
 | |
| 		}
 | |
| 
 | |
| 		if (peer->eor_stime[afi][safi] >= peer->pkt_stime[afi][safi])
 | |
| 			eor_flag = true;
 | |
| 		else
 | |
| 			eor_flag = false;
 | |
| 
 | |
| 		if (!json) {
 | |
| 			vty_out(vty, "    %s:\n",
 | |
| 				get_afi_safi_str(afi, safi, false));
 | |
| 
 | |
| 			vty_out(vty, "      F bit: ");
 | |
| 		}
 | |
| 
 | |
| 		if (peer->nsf[afi][safi] &&
 | |
| 		    CHECK_FLAG(peer->af_cap[afi][safi],
 | |
| 			       PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
 | |
| 
 | |
| 			if (json) {
 | |
| 				json_object_boolean_true_add(json_afi_safi,
 | |
| 							     "fBit");
 | |
| 			} else
 | |
| 				vty_out(vty, "True\n");
 | |
| 		} else {
 | |
| 			if (json)
 | |
| 				json_object_boolean_false_add(json_afi_safi,
 | |
| 							      "fBit");
 | |
| 			else
 | |
| 				vty_out(vty, "False\n");
 | |
| 		}
 | |
| 
 | |
| 		if (!json)
 | |
| 			vty_out(vty, "      End-of-RIB sent: ");
 | |
| 
 | |
| 		if (CHECK_FLAG(peer->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_EOR_SEND)) {
 | |
| 			if (json) {
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_endofrib_status, "endOfRibSend");
 | |
| 
 | |
| 				PRINT_EOR_JSON(eor_flag);
 | |
| 			} else {
 | |
| 				vty_out(vty, "Yes\n");
 | |
| 				vty_out(vty,
 | |
| 					"      End-of-RIB sent after update: ");
 | |
| 
 | |
| 				PRINT_EOR(eor_flag);
 | |
| 			}
 | |
| 		} else {
 | |
| 			if (json) {
 | |
| 				json_object_boolean_false_add(
 | |
| 					json_endofrib_status, "endOfRibSend");
 | |
| 				json_object_boolean_false_add(
 | |
| 					json_endofrib_status,
 | |
| 					"endOfRibSentAfterUpdate");
 | |
| 			} else {
 | |
| 				vty_out(vty, "No\n");
 | |
| 				vty_out(vty,
 | |
| 					"      End-of-RIB sent after update: ");
 | |
| 				vty_out(vty, "No\n");
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!json)
 | |
| 			vty_out(vty, "      End-of-RIB received: ");
 | |
| 
 | |
| 		if (CHECK_FLAG(peer->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_EOR_RECEIVED)) {
 | |
| 			if (json)
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_endofrib_status, "endOfRibRecv");
 | |
| 			else
 | |
| 				vty_out(vty, "Yes\n");
 | |
| 		} else {
 | |
| 			if (json)
 | |
| 				json_object_boolean_false_add(
 | |
| 					json_endofrib_status, "endOfRibRecv");
 | |
| 			else
 | |
| 				vty_out(vty, "No\n");
 | |
| 		}
 | |
| 
 | |
| 		if (json) {
 | |
| 			json_object_int_add(json_timer, "stalePathTimer",
 | |
| 					    peer->bgp->stalepath_time);
 | |
| 
 | |
| 			if (peer->t_gr_stale != NULL) {
 | |
| 				json_object_int_add(json_timer,
 | |
| 						    "stalePathTimerRemaining",
 | |
| 						    event_timer_remain_second(
 | |
| 							    peer->t_gr_stale));
 | |
| 			}
 | |
| 
 | |
| 			/* Display Configured Selection
 | |
| 			 * Deferral only when when
 | |
| 			 * Gr mode is enabled.
 | |
| 			 */
 | |
| 			if (CHECK_FLAG(peer->flags,
 | |
| 				       PEER_FLAG_GRACEFUL_RESTART)) {
 | |
| 				json_object_int_add(json_timer,
 | |
| 						    "selectionDeferralTimer",
 | |
| 						    peer->bgp->stalepath_time);
 | |
| 			}
 | |
| 
 | |
| 			if (peer->bgp->gr_info[afi][safi].t_select_deferral !=
 | |
| 			    NULL) {
 | |
| 
 | |
| 				json_object_int_add(
 | |
| 					json_timer,
 | |
| 					"selectionDeferralTimerRemaining",
 | |
| 					event_timer_remain_second(
 | |
| 						peer->bgp->gr_info[afi][safi]
 | |
| 							.t_select_deferral));
 | |
| 			}
 | |
| 		} else {
 | |
| 			vty_out(vty, "      Timers:\n");
 | |
| 			vty_out(vty,
 | |
| 				"        Configured Stale Path Time(sec): %u\n",
 | |
| 				peer->bgp->stalepath_time);
 | |
| 
 | |
| 			if (peer->t_gr_stale != NULL)
 | |
| 				vty_out(vty,
 | |
| 					"      Stale Path Remaining(sec): %ld\n",
 | |
| 					event_timer_remain_second(
 | |
| 						peer->t_gr_stale));
 | |
| 			/* Display Configured Selection
 | |
| 			 * Deferral only when when
 | |
| 			 * Gr mode is enabled.
 | |
| 			 */
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
 | |
| 				vty_out(vty,
 | |
| 					"        Configured Selection Deferral Time(sec): %u\n",
 | |
| 					peer->bgp->select_defer_time);
 | |
| 
 | |
| 			if (peer->bgp->gr_info[afi][safi].t_select_deferral !=
 | |
| 			    NULL)
 | |
| 				vty_out(vty,
 | |
| 					"        Selection Deferral Time Remaining(sec): %ld\n",
 | |
| 					event_timer_remain_second(
 | |
| 						peer->bgp->gr_info[afi][safi]
 | |
| 							.t_select_deferral));
 | |
| 		}
 | |
| 		if (json) {
 | |
| 			json_object_object_add(json_afi_safi, "endOfRibStatus",
 | |
| 					       json_endofrib_status);
 | |
| 			json_object_object_add(json_afi_safi, "timers",
 | |
| 					       json_timer);
 | |
| 			json_object_object_add(
 | |
| 				json, get_afi_safi_str(afi, safi, true),
 | |
| 				json_afi_safi);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
 | |
| 						    struct peer *p,
 | |
| 						    json_object *json)
 | |
| {
 | |
| 	if (json) {
 | |
| 		json_object *json_timer = NULL;
 | |
| 
 | |
| 		json_timer = json_object_new_object();
 | |
| 
 | |
| 		json_object_int_add(json_timer, "configuredRestartTimer",
 | |
| 				    p->bgp->restart_time);
 | |
| 
 | |
| 		json_object_int_add(json_timer, "receivedRestartTimer",
 | |
| 				    p->v_gr_restart);
 | |
| 
 | |
| 		if (p->t_gr_restart != NULL)
 | |
| 			json_object_int_add(
 | |
| 				json_timer, "restartTimerRemaining",
 | |
| 				event_timer_remain_second(p->t_gr_restart));
 | |
| 
 | |
| 		json_object_object_add(json, "timers", json_timer);
 | |
| 	} else {
 | |
| 
 | |
| 		vty_out(vty, "    Timers:\n");
 | |
| 		vty_out(vty, "      Configured Restart Time(sec): %u\n",
 | |
| 			p->bgp->restart_time);
 | |
| 
 | |
| 		vty_out(vty, "      Received Restart Time(sec): %u\n",
 | |
| 			p->v_gr_restart);
 | |
| 		if (p->t_gr_restart != NULL)
 | |
| 			vty_out(vty, "      Restart Time Remaining(sec): %ld\n",
 | |
| 				event_timer_remain_second(p->t_gr_restart));
 | |
| 		if (p->t_gr_restart != NULL) {
 | |
| 			vty_out(vty, "      Restart Time Remaining(sec): %ld\n",
 | |
| 				event_timer_remain_second(p->t_gr_restart));
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
 | |
| 				    json_object *json)
 | |
| {
 | |
| 	char dn_flag[2] = {0};
 | |
| 	/* '*' + v6 address of neighbor */
 | |
| 	char neighborAddr[INET6_ADDRSTRLEN + 1] = {0};
 | |
| 
 | |
| 	if (!p->conf_if && peer_dynamic_neighbor(p))
 | |
| 		dn_flag[0] = '*';
 | |
| 
 | |
| 	if (p->conf_if) {
 | |
| 		if (json)
 | |
| 			json_object_string_addf(json, "neighborAddr", "%pSU",
 | |
| 						&p->su);
 | |
| 		else
 | |
| 			vty_out(vty, "BGP neighbor on %s: %pSU\n", p->conf_if,
 | |
| 				&p->su);
 | |
| 	} else {
 | |
| 		snprintf(neighborAddr, sizeof(neighborAddr), "%s%s", dn_flag,
 | |
| 			 p->host);
 | |
| 
 | |
| 		if (json)
 | |
| 			json_object_string_add(json, "neighborAddr",
 | |
| 					       neighborAddr);
 | |
| 		else
 | |
| 			vty_out(vty, "BGP neighbor is %s\n", neighborAddr);
 | |
| 	}
 | |
| 
 | |
| 	/* more gr info in new format */
 | |
| 	BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json);
 | |
| }
 | |
| 
 | |
| static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
 | |
| 			      safi_t safi, bool use_json,
 | |
| 			      json_object *json_neigh)
 | |
| {
 | |
| 	struct bgp_filter *filter;
 | |
| 	struct peer_af *paf;
 | |
| 	char orf_pfx_name[BUFSIZ];
 | |
| 	int orf_pfx_count;
 | |
| 	json_object *json_af = NULL;
 | |
| 	json_object *json_prefA = NULL;
 | |
| 	json_object *json_prefB = NULL;
 | |
| 	json_object *json_addr = NULL;
 | |
| 	json_object *json_advmap = NULL;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_addr = json_object_new_object();
 | |
| 		json_af = json_object_new_object();
 | |
| 		filter = &p->filter[afi][safi];
 | |
| 
 | |
| 		if (peer_group_active(p))
 | |
| 			json_object_string_add(json_addr, "peerGroupMember",
 | |
| 					       p->group->name);
 | |
| 
 | |
| 		paf = peer_af_find(p, afi, safi);
 | |
| 		if (paf && PAF_SUBGRP(paf)) {
 | |
| 			json_object_int_add(json_addr, "updateGroupId",
 | |
| 					    PAF_UPDGRP(paf)->id);
 | |
| 			json_object_int_add(json_addr, "subGroupId",
 | |
| 					    PAF_SUBGRP(paf)->id);
 | |
| 			json_object_int_add(json_addr, "packetQueueLength",
 | |
| 					    bpacket_queue_virtual_length(paf));
 | |
| 		}
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_RCV)) {
 | |
| 			json_object_int_add(json_af, "orfType",
 | |
| 					    ORF_TYPE_PREFIX);
 | |
| 			json_prefA = json_object_new_object();
 | |
| 			bgp_show_peer_afi_orf_cap(vty, p, afi, safi,
 | |
| 						  PEER_CAP_ORF_PREFIX_SM_ADV,
 | |
| 						  PEER_CAP_ORF_PREFIX_RM_ADV,
 | |
| 						  PEER_CAP_ORF_PREFIX_SM_RCV,
 | |
| 						  PEER_CAP_ORF_PREFIX_RM_RCV,
 | |
| 						  use_json, json_prefA);
 | |
| 			json_object_object_add(json_af, "orfPrefixList",
 | |
| 					       json_prefA);
 | |
| 		}
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) {
 | |
| 			json_object_int_add(json_af, "orfOldType",
 | |
| 					    ORF_TYPE_PREFIX_OLD);
 | |
| 			json_prefB = json_object_new_object();
 | |
| 			bgp_show_peer_afi_orf_cap(
 | |
| 				vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_SM_OLD_RCV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_OLD_RCV, use_json,
 | |
| 				json_prefB);
 | |
| 			json_object_object_add(json_af, "orfOldPrefixList",
 | |
| 					       json_prefB);
 | |
| 		}
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
 | |
| 			json_object_object_add(json_addr, "afDependentCap",
 | |
| 					       json_af);
 | |
| 		else
 | |
| 			json_object_free(json_af);
 | |
| 
 | |
| 		snprintf(orf_pfx_name, sizeof(orf_pfx_name), "%s.%d.%d",
 | |
| 			 p->host, afi, safi);
 | |
| 		orf_pfx_count = prefix_bgp_show_prefix_list(
 | |
| 			NULL, afi, orf_pfx_name, use_json);
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_ORF_PREFIX_SEND)
 | |
| 		    || orf_pfx_count) {
 | |
| 			if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 				       PEER_STATUS_ORF_PREFIX_SEND))
 | |
| 				json_object_boolean_true_add(json_neigh,
 | |
| 							     "orfSent");
 | |
| 			if (orf_pfx_count)
 | |
| 				json_object_int_add(json_addr, "orfRecvCounter",
 | |
| 						    orf_pfx_count);
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_ORF_WAIT_REFRESH))
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "orfFirstUpdate",
 | |
| 				"deferredUntilORFOrRouteRefreshRecvd");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_REFLECTOR_CLIENT))
 | |
| 			json_object_boolean_true_add(json_addr,
 | |
| 						     "routeReflectorClient");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_RSERVER_CLIENT))
 | |
| 			json_object_boolean_true_add(json_addr,
 | |
| 						     "routeServerClient");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
 | |
| 			json_object_boolean_true_add(json_addr,
 | |
| 						     "inboundSoftConfigPermit");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr,
 | |
| 				"privateAsNumsAllReplacedInUpdatesToNbr");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr,
 | |
| 				"privateAsNumsReplacedInUpdatesToNbr");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr,
 | |
| 				"privateAsNumsAllRemovedInUpdatesToNbr");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr,
 | |
| 				"privateAsNumsRemovedInUpdatesToNbr");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) {
 | |
| 			if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				       PEER_FLAG_ALLOWAS_IN_ORIGIN))
 | |
| 				json_object_boolean_true_add(json_addr,
 | |
| 							     "allowAsInOrigin");
 | |
| 			else
 | |
| 				json_object_int_add(json_addr, "allowAsInCount",
 | |
| 						    p->allowas_in[afi][safi]);
 | |
| 		}
 | |
| 
 | |
| 		if (p->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr,
 | |
| 				bgp_addpath_names(p->addpath_type[afi][safi])
 | |
| 					->type_json_name);
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "overrideASNsInOutboundUpdates",
 | |
| 					       "ifAspathEqualRemoteAs");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
 | |
| 		    || CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				  PEER_FLAG_FORCE_NEXTHOP_SELF))
 | |
| 			json_object_boolean_true_add(json_addr,
 | |
| 						     "routerAlwaysNextHop");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_AS_PATH_UNCHANGED))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr, "unchangedAsPathPropogatedToNbr");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_NEXTHOP_UNCHANGED))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr, "unchangedNextHopPropogatedToNbr");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr, "unchangedMedPropogatedToNbr");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
 | |
| 		    || CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				  PEER_FLAG_SEND_EXT_COMMUNITY)) {
 | |
| 			if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				       PEER_FLAG_SEND_COMMUNITY)
 | |
| 			    && CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					  PEER_FLAG_SEND_EXT_COMMUNITY))
 | |
| 				json_object_string_add(json_addr,
 | |
| 						       "commAttriSentToNbr",
 | |
| 						       "extendedAndStandard");
 | |
| 			else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					    PEER_FLAG_SEND_EXT_COMMUNITY))
 | |
| 				json_object_string_add(json_addr,
 | |
| 						       "commAttriSentToNbr",
 | |
| 						       "extended");
 | |
| 			else
 | |
| 				json_object_string_add(json_addr,
 | |
| 						       "commAttriSentToNbr",
 | |
| 						       "standard");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_DEFAULT_ORIGINATE)) {
 | |
| 			if (p->default_rmap[afi][safi].name)
 | |
| 				json_object_string_add(
 | |
| 					json_addr, "defaultRouteMap",
 | |
| 					p->default_rmap[afi][safi].name);
 | |
| 
 | |
| 			if (paf && PAF_SUBGRP(paf)
 | |
| 			    && CHECK_FLAG(PAF_SUBGRP(paf)->sflags,
 | |
| 					  SUBGRP_STATUS_DEFAULT_ORIGINATE))
 | |
| 				json_object_boolean_true_add(json_addr,
 | |
| 							     "defaultSent");
 | |
| 			else
 | |
| 				json_object_boolean_true_add(json_addr,
 | |
| 							     "defaultNotSent");
 | |
| 		}
 | |
| 
 | |
| 		if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
 | |
| 			if (is_evpn_enabled())
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_addr, "advertiseAllVnis");
 | |
| 		}
 | |
| 
 | |
| 		if (filter->plist[FILTER_IN].name
 | |
| 		    || filter->dlist[FILTER_IN].name
 | |
| 		    || filter->aslist[FILTER_IN].name
 | |
| 		    || filter->map[RMAP_IN].name)
 | |
| 			json_object_boolean_true_add(json_addr,
 | |
| 						     "inboundPathPolicyConfig");
 | |
| 		if (filter->plist[FILTER_OUT].name
 | |
| 		    || filter->dlist[FILTER_OUT].name
 | |
| 		    || filter->aslist[FILTER_OUT].name
 | |
| 		    || filter->map[RMAP_OUT].name || filter->usmap.name)
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_addr, "outboundPathPolicyConfig");
 | |
| 
 | |
| 		/* prefix-list */
 | |
| 		if (filter->plist[FILTER_IN].name)
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "incomingUpdatePrefixFilterList",
 | |
| 					       filter->plist[FILTER_IN].name);
 | |
| 		if (filter->plist[FILTER_OUT].name)
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "outgoingUpdatePrefixFilterList",
 | |
| 					       filter->plist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* distribute-list */
 | |
| 		if (filter->dlist[FILTER_IN].name)
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "incomingUpdateNetworkFilterList",
 | |
| 				filter->dlist[FILTER_IN].name);
 | |
| 		if (filter->dlist[FILTER_OUT].name)
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "outgoingUpdateNetworkFilterList",
 | |
| 				filter->dlist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* filter-list. */
 | |
| 		if (filter->aslist[FILTER_IN].name)
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "incomingUpdateAsPathFilterList",
 | |
| 					       filter->aslist[FILTER_IN].name);
 | |
| 		if (filter->aslist[FILTER_OUT].name)
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "outgoingUpdateAsPathFilterList",
 | |
| 					       filter->aslist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* route-map. */
 | |
| 		if (filter->map[RMAP_IN].name)
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "routeMapForIncomingAdvertisements",
 | |
| 				filter->map[RMAP_IN].name);
 | |
| 		if (filter->map[RMAP_OUT].name)
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "routeMapForOutgoingAdvertisements",
 | |
| 				filter->map[RMAP_OUT].name);
 | |
| 
 | |
| 		/* ebgp-requires-policy (inbound) */
 | |
| 		if (CHECK_FLAG(p->bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 		    && !bgp_inbound_policy_exists(p, filter))
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "inboundEbgpRequiresPolicy",
 | |
| 				"Inbound updates discarded due to missing policy");
 | |
| 
 | |
| 		/* ebgp-requires-policy (outbound) */
 | |
| 		if (CHECK_FLAG(p->bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 		    && (!bgp_outbound_policy_exists(p, filter)))
 | |
| 			json_object_string_add(
 | |
| 				json_addr, "outboundEbgpRequiresPolicy",
 | |
| 				"Outbound updates discarded due to missing policy");
 | |
| 
 | |
| 		/* unsuppress-map */
 | |
| 		if (filter->usmap.name)
 | |
| 			json_object_string_add(json_addr,
 | |
| 					       "selectiveUnsuppressRouteMap",
 | |
| 					       filter->usmap.name);
 | |
| 
 | |
| 		/* advertise-map */
 | |
| 		if (filter->advmap.aname) {
 | |
| 			json_advmap = json_object_new_object();
 | |
| 			json_object_string_add(json_advmap, "condition",
 | |
| 					       filter->advmap.condition
 | |
| 						       ? "EXIST"
 | |
| 						       : "NON_EXIST");
 | |
| 			json_object_string_add(json_advmap, "conditionMap",
 | |
| 					       filter->advmap.cname);
 | |
| 			json_object_string_add(json_advmap, "advertiseMap",
 | |
| 					       filter->advmap.aname);
 | |
| 			json_object_string_add(
 | |
| 				json_advmap, "advertiseStatus",
 | |
| 				filter->advmap.update_type ==
 | |
| 						UPDATE_TYPE_ADVERTISE
 | |
| 					? "Advertise"
 | |
| 					: "Withdraw");
 | |
| 			json_object_object_add(json_addr, "advertiseMap",
 | |
| 					       json_advmap);
 | |
| 		}
 | |
| 
 | |
| 		/* Receive prefix count */
 | |
| 		json_object_int_add(json_addr, "acceptedPrefixCounter",
 | |
| 				    p->pcount[afi][safi]);
 | |
| 		if (paf && PAF_SUBGRP(paf))
 | |
| 			json_object_int_add(json_addr, "sentPrefixCounter",
 | |
| 						(PAF_SUBGRP(paf))->scount);
 | |
| 
 | |
| 		/* Maximum prefix */
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
 | |
| 			json_object_int_add(json_addr, "prefixOutAllowedMax",
 | |
| 					    p->pmax_out[afi][safi]);
 | |
| 
 | |
| 		/* Maximum prefix */
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
 | |
| 			json_object_int_add(json_addr, "prefixAllowedMax",
 | |
| 					    p->pmax[afi][safi]);
 | |
| 			if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				       PEER_FLAG_MAX_PREFIX_WARNING))
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_addr, "prefixAllowedMaxWarning");
 | |
| 			json_object_int_add(json_addr,
 | |
| 					    "prefixAllowedWarningThresh",
 | |
| 					    p->pmax_threshold[afi][safi]);
 | |
| 			if (p->pmax_restart[afi][safi])
 | |
| 				json_object_int_add(
 | |
| 					json_addr,
 | |
| 					"prefixAllowedRestartIntervalMsecs",
 | |
| 					p->pmax_restart[afi][safi] * 60000);
 | |
| 		}
 | |
| 		json_object_object_add(json_neigh,
 | |
| 				       get_afi_safi_str(afi, safi, true),
 | |
| 				       json_addr);
 | |
| 
 | |
| 	} else {
 | |
| 		filter = &p->filter[afi][safi];
 | |
| 
 | |
| 		vty_out(vty, " For address family: %s\n",
 | |
| 			get_afi_safi_str(afi, safi, false));
 | |
| 
 | |
| 		if (peer_group_active(p))
 | |
| 			vty_out(vty, "  %s peer-group member\n",
 | |
| 				p->group->name);
 | |
| 
 | |
| 		paf = peer_af_find(p, afi, safi);
 | |
| 		if (paf && PAF_SUBGRP(paf)) {
 | |
| 			vty_out(vty, "  Update group %" PRIu64", subgroup %" PRIu64 "\n",
 | |
| 				PAF_UPDGRP(paf)->id, PAF_SUBGRP(paf)->id);
 | |
| 			vty_out(vty, "  Packet Queue length %d\n",
 | |
| 				bpacket_queue_virtual_length(paf));
 | |
| 		} else {
 | |
| 			vty_out(vty, "  Not part of any update group\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
 | |
| 			vty_out(vty, "  AF-dependant capabilities:\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_RCV)) {
 | |
| 			vty_out(vty,
 | |
| 				"    Outbound Route Filter (ORF) type (%d) Prefix-list:\n",
 | |
| 				ORF_TYPE_PREFIX);
 | |
| 			bgp_show_peer_afi_orf_cap(
 | |
| 				vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_SM_RCV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_RCV, use_json, NULL);
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_ADV)
 | |
| 		    || CHECK_FLAG(p->af_cap[afi][safi],
 | |
| 				  PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) {
 | |
| 			vty_out(vty,
 | |
| 				"    Outbound Route Filter (ORF) type (%d) Prefix-list:\n",
 | |
| 				ORF_TYPE_PREFIX_OLD);
 | |
| 			bgp_show_peer_afi_orf_cap(
 | |
| 				vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_ADV,
 | |
| 				PEER_CAP_ORF_PREFIX_SM_OLD_RCV,
 | |
| 				PEER_CAP_ORF_PREFIX_RM_OLD_RCV, use_json, NULL);
 | |
| 		}
 | |
| 
 | |
| 		snprintf(orf_pfx_name, sizeof(orf_pfx_name), "%s.%d.%d",
 | |
| 			 p->host, afi, safi);
 | |
| 		orf_pfx_count = prefix_bgp_show_prefix_list(
 | |
| 			NULL, afi, orf_pfx_name, use_json);
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_ORF_PREFIX_SEND)
 | |
| 		    || orf_pfx_count) {
 | |
| 			vty_out(vty, "  Outbound Route Filter (ORF):");
 | |
| 			if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 				       PEER_STATUS_ORF_PREFIX_SEND))
 | |
| 				vty_out(vty, " sent;");
 | |
| 			if (orf_pfx_count)
 | |
| 				vty_out(vty, " received (%d entries)",
 | |
| 					orf_pfx_count);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 			       PEER_STATUS_ORF_WAIT_REFRESH))
 | |
| 			vty_out(vty,
 | |
| 				"  First update is deferred until ORF or ROUTE-REFRESH is received\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_REFLECTOR_CLIENT))
 | |
| 			vty_out(vty, "  Route-Reflector Client\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_RSERVER_CLIENT))
 | |
| 			vty_out(vty, "  Route-Server Client\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
 | |
| 			vty_out(vty,
 | |
| 				"  Inbound soft reconfiguration allowed\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE))
 | |
| 			vty_out(vty,
 | |
| 				"  Private AS numbers (all) replaced in updates to this neighbor\n");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
 | |
| 			vty_out(vty,
 | |
| 				"  Private AS numbers replaced in updates to this neighbor\n");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
 | |
| 			vty_out(vty,
 | |
| 				"  Private AS numbers (all) removed in updates to this neighbor\n");
 | |
| 		else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS))
 | |
| 			vty_out(vty,
 | |
| 				"  Private AS numbers removed in updates to this neighbor\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) {
 | |
| 			if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				       PEER_FLAG_ALLOWAS_IN_ORIGIN))
 | |
| 				vty_out(vty,
 | |
| 					"  Local AS allowed as path origin\n");
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"  Local AS allowed in path, %d occurrences\n",
 | |
| 					p->allowas_in[afi][safi]);
 | |
| 		}
 | |
| 
 | |
| 		if (p->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
 | |
| 			vty_out(vty, "  %s\n",
 | |
| 				bgp_addpath_names(p->addpath_type[afi][safi])
 | |
| 					->human_description);
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
 | |
| 			vty_out(vty,
 | |
| 				"  Override ASNs in outbound updates if aspath equals remote-as\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
 | |
| 		    || CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				  PEER_FLAG_FORCE_NEXTHOP_SELF))
 | |
| 			vty_out(vty, "  NEXT_HOP is always this router\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_AS_PATH_UNCHANGED))
 | |
| 			vty_out(vty,
 | |
| 				"  AS_PATH is propagated unchanged to this neighbor\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_NEXTHOP_UNCHANGED))
 | |
| 			vty_out(vty,
 | |
| 				"  NEXT_HOP is propagated unchanged to this neighbor\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
 | |
| 			vty_out(vty,
 | |
| 				"  MED is propagated unchanged to this neighbor\n");
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
 | |
| 		    || CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				  PEER_FLAG_SEND_EXT_COMMUNITY)
 | |
| 		    || CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				  PEER_FLAG_SEND_LARGE_COMMUNITY)) {
 | |
| 			vty_out(vty,
 | |
| 				"  Community attribute sent to this neighbor");
 | |
| 			if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 				       PEER_FLAG_SEND_COMMUNITY)
 | |
| 			    && CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					  PEER_FLAG_SEND_EXT_COMMUNITY)
 | |
| 			    && CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					  PEER_FLAG_SEND_LARGE_COMMUNITY))
 | |
| 				vty_out(vty, "(all)\n");
 | |
| 			else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					    PEER_FLAG_SEND_LARGE_COMMUNITY))
 | |
| 				vty_out(vty, "(large)\n");
 | |
| 			else if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					    PEER_FLAG_SEND_EXT_COMMUNITY))
 | |
| 				vty_out(vty, "(extended)\n");
 | |
| 			else
 | |
| 				vty_out(vty, "(standard)\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_DEFAULT_ORIGINATE)) {
 | |
| 			vty_out(vty, "  Default information originate,");
 | |
| 
 | |
| 			if (p->default_rmap[afi][safi].name)
 | |
| 				vty_out(vty, " default route-map %s%s,",
 | |
| 					p->default_rmap[afi][safi].map ? "*"
 | |
| 								       : "",
 | |
| 					p->default_rmap[afi][safi].name);
 | |
| 			if (paf && PAF_SUBGRP(paf)
 | |
| 			    && CHECK_FLAG(PAF_SUBGRP(paf)->sflags,
 | |
| 					  SUBGRP_STATUS_DEFAULT_ORIGINATE))
 | |
| 				vty_out(vty, " default sent\n");
 | |
| 			else
 | |
| 				vty_out(vty, " default not sent\n");
 | |
| 		}
 | |
| 
 | |
| 		/* advertise-vni-all */
 | |
| 		if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
 | |
| 			if (is_evpn_enabled())
 | |
| 				vty_out(vty, "  advertise-all-vni\n");
 | |
| 		}
 | |
| 
 | |
| 		if (filter->plist[FILTER_IN].name
 | |
| 		    || filter->dlist[FILTER_IN].name
 | |
| 		    || filter->aslist[FILTER_IN].name
 | |
| 		    || filter->map[RMAP_IN].name)
 | |
| 			vty_out(vty, "  Inbound path policy configured\n");
 | |
| 		if (filter->plist[FILTER_OUT].name
 | |
| 		    || filter->dlist[FILTER_OUT].name
 | |
| 		    || filter->aslist[FILTER_OUT].name
 | |
| 		    || filter->map[RMAP_OUT].name || filter->usmap.name)
 | |
| 			vty_out(vty, "  Outbound path policy configured\n");
 | |
| 
 | |
| 		/* prefix-list */
 | |
| 		if (filter->plist[FILTER_IN].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Incoming update prefix filter list is %s%s\n",
 | |
| 				filter->plist[FILTER_IN].plist ? "*" : "",
 | |
| 				filter->plist[FILTER_IN].name);
 | |
| 		if (filter->plist[FILTER_OUT].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Outgoing update prefix filter list is %s%s\n",
 | |
| 				filter->plist[FILTER_OUT].plist ? "*" : "",
 | |
| 				filter->plist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* distribute-list */
 | |
| 		if (filter->dlist[FILTER_IN].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Incoming update network filter list is %s%s\n",
 | |
| 				filter->dlist[FILTER_IN].alist ? "*" : "",
 | |
| 				filter->dlist[FILTER_IN].name);
 | |
| 		if (filter->dlist[FILTER_OUT].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Outgoing update network filter list is %s%s\n",
 | |
| 				filter->dlist[FILTER_OUT].alist ? "*" : "",
 | |
| 				filter->dlist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* filter-list. */
 | |
| 		if (filter->aslist[FILTER_IN].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Incoming update AS path filter list is %s%s\n",
 | |
| 				filter->aslist[FILTER_IN].aslist ? "*" : "",
 | |
| 				filter->aslist[FILTER_IN].name);
 | |
| 		if (filter->aslist[FILTER_OUT].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Outgoing update AS path filter list is %s%s\n",
 | |
| 				filter->aslist[FILTER_OUT].aslist ? "*" : "",
 | |
| 				filter->aslist[FILTER_OUT].name);
 | |
| 
 | |
| 		/* route-map. */
 | |
| 		if (filter->map[RMAP_IN].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Route map for incoming advertisements is %s%s\n",
 | |
| 				filter->map[RMAP_IN].map ? "*" : "",
 | |
| 				filter->map[RMAP_IN].name);
 | |
| 		if (filter->map[RMAP_OUT].name)
 | |
| 			vty_out(vty,
 | |
| 				"  Route map for outgoing advertisements is %s%s\n",
 | |
| 				filter->map[RMAP_OUT].map ? "*" : "",
 | |
| 				filter->map[RMAP_OUT].name);
 | |
| 
 | |
| 		/* ebgp-requires-policy (inbound) */
 | |
| 		if (CHECK_FLAG(p->bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 		    && !bgp_inbound_policy_exists(p, filter))
 | |
| 			vty_out(vty,
 | |
| 				"  Inbound updates discarded due to missing policy\n");
 | |
| 
 | |
| 		/* ebgp-requires-policy (outbound) */
 | |
| 		if (CHECK_FLAG(p->bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 		    && !bgp_outbound_policy_exists(p, filter))
 | |
| 			vty_out(vty,
 | |
| 				"  Outbound updates discarded due to missing policy\n");
 | |
| 
 | |
| 		/* unsuppress-map */
 | |
| 		if (filter->usmap.name)
 | |
| 			vty_out(vty,
 | |
| 				"  Route map for selective unsuppress is %s%s\n",
 | |
| 				filter->usmap.map ? "*" : "",
 | |
| 				filter->usmap.name);
 | |
| 
 | |
| 		/* advertise-map */
 | |
| 		if (filter->advmap.aname && filter->advmap.cname)
 | |
| 			vty_out(vty,
 | |
| 				"  Condition %s, Condition-map %s%s, Advertise-map %s%s, status: %s\n",
 | |
| 				filter->advmap.condition ? "EXIST"
 | |
| 							 : "NON_EXIST",
 | |
| 				filter->advmap.cmap ? "*" : "",
 | |
| 				filter->advmap.cname,
 | |
| 				filter->advmap.amap ? "*" : "",
 | |
| 				filter->advmap.aname,
 | |
| 				filter->advmap.update_type ==
 | |
| 						UPDATE_TYPE_ADVERTISE
 | |
| 					? "Advertise"
 | |
| 					: "Withdraw");
 | |
| 
 | |
| 		/* Receive prefix count */
 | |
| 		vty_out(vty, "  %u accepted prefixes\n",
 | |
| 			p->pcount[afi][safi]);
 | |
| 
 | |
| 		/* maximum-prefix-out */
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 			       PEER_FLAG_MAX_PREFIX_OUT))
 | |
| 			vty_out(vty,
 | |
| 				"  Maximum allowed prefixes sent %u\n",
 | |
| 				p->pmax_out[afi][safi]);
 | |
| 
 | |
| 		/* Maximum prefix */
 | |
| 		if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
 | |
| 			vty_out(vty,
 | |
| 				"  Maximum prefixes allowed %u%s\n",
 | |
| 				p->pmax[afi][safi],
 | |
| 				CHECK_FLAG(p->af_flags[afi][safi],
 | |
| 					   PEER_FLAG_MAX_PREFIX_WARNING)
 | |
| 					? " (warning-only)"
 | |
| 					: "");
 | |
| 			vty_out(vty, "  Threshold for warning message %d%%",
 | |
| 				p->pmax_threshold[afi][safi]);
 | |
| 			if (p->pmax_restart[afi][safi])
 | |
| 				vty_out(vty, ", restart interval %d min",
 | |
| 					p->pmax_restart[afi][safi]);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
 | |
| 			  json_object *json)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	char timebuf[BGP_UPTIME_LEN];
 | |
| 	char dn_flag[2];
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	uint16_t i;
 | |
| 	uint8_t *msg;
 | |
| 	json_object *json_neigh = NULL;
 | |
| 	time_t epoch_tbuf;
 | |
| 	uint32_t sync_tcp_mss;
 | |
| 
 | |
| 	bgp = p->bgp;
 | |
| 
 | |
| 	if (use_json)
 | |
| 		json_neigh = json_object_new_object();
 | |
| 
 | |
| 	memset(dn_flag, '\0', sizeof(dn_flag));
 | |
| 	if (!p->conf_if && peer_dynamic_neighbor(p))
 | |
| 		dn_flag[0] = '*';
 | |
| 
 | |
| 	if (!use_json) {
 | |
| 		if (p->conf_if) /* Configured interface name. */
 | |
| 			vty_out(vty, "BGP neighbor on %s: %pSU, ", p->conf_if,
 | |
| 				&p->su);
 | |
| 		else /* Configured IP address. */
 | |
| 			vty_out(vty, "BGP neighbor is %s%s, ", dn_flag,
 | |
| 				p->host);
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		if (p->conf_if && BGP_PEER_SU_UNSPEC(p))
 | |
| 			json_object_string_add(json_neigh, "bgpNeighborAddr",
 | |
| 					       "none");
 | |
| 		else if (p->conf_if && !BGP_PEER_SU_UNSPEC(p))
 | |
| 			json_object_string_addf(json_neigh, "bgpNeighborAddr",
 | |
| 						"%pSU", &p->su);
 | |
| 
 | |
| 		asn_asn2json(json_neigh, "remoteAs", p->as, bgp->asnotation);
 | |
| 
 | |
| 		if (p->change_local_as)
 | |
| 			asn_asn2json(json_neigh, "localAs", p->change_local_as,
 | |
| 				     bgp->asnotation);
 | |
| 		else
 | |
| 			asn_asn2json(json_neigh, "localAs", p->local_as,
 | |
| 				     bgp->asnotation);
 | |
| 
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "localAsNoPrepend");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS))
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "localAsReplaceAs");
 | |
| 	} else {
 | |
| 		if ((p->as_type == AS_SPECIFIED) ||
 | |
| 		    (p->as_type == AS_EXTERNAL) ||
 | |
| 		    (p->as_type == AS_INTERNAL)) {
 | |
| 			vty_out(vty, "remote AS ");
 | |
| 			vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
 | |
| 			vty_out(vty, ", ");
 | |
| 		} else
 | |
| 			vty_out(vty, "remote AS Unspecified, ");
 | |
| 		vty_out(vty, "local AS ");
 | |
| 		vty_out(vty, ASN_FORMAT(bgp->asnotation),
 | |
| 			p->change_local_as ? &p->change_local_as
 | |
| 					   : &p->local_as);
 | |
| 		vty_out(vty, "%s%s, ",
 | |
| 			CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
 | |
| 				? " no-prepend"
 | |
| 				: "",
 | |
| 			CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
 | |
| 				? " replace-as"
 | |
| 				: "");
 | |
| 	}
 | |
| 	/* peer type internal or confed-internal */
 | |
| 	if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) {
 | |
| 		if (use_json) {
 | |
| 			if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_neigh, "nbrConfedInternalLink");
 | |
| 			else
 | |
| 				json_object_boolean_true_add(json_neigh,
 | |
| 							     "nbrInternalLink");
 | |
| 		} else {
 | |
| 			if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
 | |
| 				vty_out(vty, "confed-internal link\n");
 | |
| 			else
 | |
| 				vty_out(vty, "internal link\n");
 | |
| 		}
 | |
| 	/* peer type external or confed-external */
 | |
| 	} else if (p->as || (p->as_type == AS_EXTERNAL)) {
 | |
| 		if (use_json) {
 | |
| 			if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_neigh, "nbrConfedExternalLink");
 | |
| 			else
 | |
| 				json_object_boolean_true_add(json_neigh,
 | |
| 							     "nbrExternalLink");
 | |
| 		} else {
 | |
| 			if (bgp_confederation_peers_check(bgp, p->as))
 | |
| 				vty_out(vty, "confed-external link\n");
 | |
| 			else
 | |
| 				vty_out(vty, "external link\n");
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (use_json)
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "nbrUnspecifiedLink");
 | |
| 		else
 | |
| 			vty_out(vty, "unspecified link\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Roles */
 | |
| 	if (use_json) {
 | |
| 		json_object_string_add(json_neigh, "localRole",
 | |
| 				       bgp_get_name_by_role(p->local_role));
 | |
| 		json_object_string_add(json_neigh, "remoteRole",
 | |
| 				       bgp_get_name_by_role(p->remote_role));
 | |
| 	} else {
 | |
| 		vty_out(vty, "  Local Role: %s\n",
 | |
| 			bgp_get_name_by_role(p->local_role));
 | |
| 		vty_out(vty, "  Remote Role: %s\n",
 | |
| 			bgp_get_name_by_role(p->remote_role));
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/* Description. */
 | |
| 	if (p->desc) {
 | |
| 		if (use_json)
 | |
| 			json_object_string_add(json_neigh, "nbrDesc", p->desc);
 | |
| 		else
 | |
| 			vty_out(vty, " Description: %s\n", p->desc);
 | |
| 	}
 | |
| 
 | |
| 	if (p->hostname) {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_add(json_neigh, "hostname",
 | |
| 					       p->hostname);
 | |
| 
 | |
| 			if (p->domainname)
 | |
| 				json_object_string_add(json_neigh, "domainname",
 | |
| 						       p->domainname);
 | |
| 		} else {
 | |
| 			if (p->domainname && (p->domainname[0] != '\0'))
 | |
| 				vty_out(vty, "Hostname: %s.%s\n", p->hostname,
 | |
| 					p->domainname);
 | |
| 			else
 | |
| 				vty_out(vty, "Hostname: %s\n", p->hostname);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (use_json)
 | |
| 			json_object_string_add(json_neigh, "hostname",
 | |
| 					       "Unknown");
 | |
| 	}
 | |
| 
 | |
| 	/* Peer-group */
 | |
| 	if (p->group) {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_add(json_neigh, "peerGroup",
 | |
| 					       p->group->name);
 | |
| 
 | |
| 			if (dn_flag[0]) {
 | |
| 				struct prefix prefix, *range = NULL;
 | |
| 
 | |
| 				if (sockunion2hostprefix(&(p->su), &prefix))
 | |
| 					range = peer_group_lookup_dynamic_neighbor_range(
 | |
| 						p->group, &prefix);
 | |
| 
 | |
| 				if (range) {
 | |
| 					json_object_string_addf(
 | |
| 						json_neigh,
 | |
| 						"peerSubnetRangeGroup", "%pFX",
 | |
| 						range);
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			vty_out(vty,
 | |
| 				" Member of peer-group %s for session parameters\n",
 | |
| 				p->group->name);
 | |
| 
 | |
| 			if (dn_flag[0]) {
 | |
| 				struct prefix prefix, *range = NULL;
 | |
| 
 | |
| 				if (sockunion2hostprefix(&(p->su), &prefix))
 | |
| 					range = peer_group_lookup_dynamic_neighbor_range(
 | |
| 						p->group, &prefix);
 | |
| 
 | |
| 				if (range) {
 | |
| 					vty_out(vty,
 | |
| 						" Belongs to the subnet range group: %pFX\n",
 | |
| 						range);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		/* Administrative shutdown. */
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_SHUTDOWN)
 | |
| 		    || CHECK_FLAG(p->bgp->flags, BGP_FLAG_SHUTDOWN))
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "adminShutDown");
 | |
| 
 | |
| 		/* BGP Version. */
 | |
| 		json_object_int_add(json_neigh, "bgpVersion", 4);
 | |
| 		json_object_string_addf(json_neigh, "remoteRouterId", "%pI4",
 | |
| 					&p->remote_id);
 | |
| 		json_object_string_addf(json_neigh, "localRouterId", "%pI4",
 | |
| 					&bgp->router_id);
 | |
| 
 | |
| 		/* Confederation */
 | |
| 		if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
 | |
| 		    && bgp_confederation_peers_check(bgp, p->as))
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "nbrCommonAdmin");
 | |
| 
 | |
| 		/* Status. */
 | |
| 		json_object_string_add(
 | |
| 			json_neigh, "bgpState",
 | |
| 			lookup_msg(bgp_status_msg, p->status, NULL));
 | |
| 
 | |
| 		if (peer_established(p)) {
 | |
| 			time_t uptime;
 | |
| 
 | |
| 			uptime = monotime(NULL);
 | |
| 			uptime -= p->uptime;
 | |
| 			epoch_tbuf = time(NULL) - uptime;
 | |
| 
 | |
| 			json_object_int_add(json_neigh, "bgpTimerUpMsec",
 | |
| 					    uptime * 1000);
 | |
| 			json_object_string_add(json_neigh, "bgpTimerUpString",
 | |
| 					       peer_uptime(p->uptime, timebuf,
 | |
| 							   BGP_UPTIME_LEN, 0,
 | |
| 							   NULL));
 | |
| 			json_object_int_add(json_neigh,
 | |
| 					    "bgpTimerUpEstablishedEpoch",
 | |
| 					    epoch_tbuf);
 | |
| 		}
 | |
| 
 | |
| 		else if (p->status == Active) {
 | |
| 			if (CHECK_FLAG(p->flags, PEER_FLAG_PASSIVE))
 | |
| 				json_object_string_add(json_neigh, "bgpStateIs",
 | |
| 						       "passive");
 | |
| 			else if (CHECK_FLAG(p->sflags, PEER_STATUS_NSF_WAIT))
 | |
| 				json_object_string_add(json_neigh, "bgpStateIs",
 | |
| 						       "passiveNSF");
 | |
| 		}
 | |
| 
 | |
| 		/* read timer */
 | |
| 		time_t uptime;
 | |
| 		struct tm tm;
 | |
| 
 | |
| 		uptime = monotime(NULL);
 | |
| 		uptime -= p->readtime;
 | |
| 		gmtime_r(&uptime, &tm);
 | |
| 
 | |
| 		json_object_int_add(json_neigh, "bgpTimerLastRead",
 | |
| 				    (tm.tm_sec * 1000) + (tm.tm_min * 60000)
 | |
| 					    + (tm.tm_hour * 3600000));
 | |
| 
 | |
| 		uptime = monotime(NULL);
 | |
| 		uptime -= p->last_write;
 | |
| 		gmtime_r(&uptime, &tm);
 | |
| 
 | |
| 		json_object_int_add(json_neigh, "bgpTimerLastWrite",
 | |
| 				    (tm.tm_sec * 1000) + (tm.tm_min * 60000)
 | |
| 					    + (tm.tm_hour * 3600000));
 | |
| 
 | |
| 		uptime = monotime(NULL);
 | |
| 		uptime -= p->update_time;
 | |
| 		gmtime_r(&uptime, &tm);
 | |
| 
 | |
| 		json_object_int_add(json_neigh, "bgpInUpdateElapsedTimeMsecs",
 | |
| 				    (tm.tm_sec * 1000) + (tm.tm_min * 60000)
 | |
| 					    + (tm.tm_hour * 3600000));
 | |
| 
 | |
| 		/* Configured timer values. */
 | |
| 		json_object_int_add(json_neigh,
 | |
| 				    "bgpTimerConfiguredHoldTimeMsecs",
 | |
| 				    CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
 | |
| 					    ? p->holdtime * 1000
 | |
| 					    : bgp->default_holdtime * 1000);
 | |
| 		json_object_int_add(json_neigh,
 | |
| 				    "bgpTimerConfiguredKeepAliveIntervalMsecs",
 | |
| 				    CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
 | |
| 					    ? p->keepalive * 1000
 | |
| 					    : bgp->default_keepalive * 1000);
 | |
| 		json_object_int_add(json_neigh, "bgpTimerHoldTimeMsecs",
 | |
| 				    p->v_holdtime * 1000);
 | |
| 		json_object_int_add(json_neigh,
 | |
| 				    "bgpTimerKeepAliveIntervalMsecs",
 | |
| 				    p->v_keepalive * 1000);
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER_DELAYOPEN)) {
 | |
| 			json_object_int_add(json_neigh,
 | |
| 					    "bgpTimerDelayOpenTimeMsecs",
 | |
| 					    p->v_delayopen * 1000);
 | |
| 		}
 | |
| 
 | |
| 		/* Configured and Synced tcp-mss value for peer */
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) {
 | |
| 			sync_tcp_mss = sockopt_tcp_mss_get(p->fd);
 | |
| 			json_object_int_add(json_neigh, "bgpTcpMssConfigured",
 | |
| 					    p->tcp_mss);
 | |
| 			json_object_int_add(json_neigh, "bgpTcpMssSynced",
 | |
| 					    sync_tcp_mss);
 | |
| 		}
 | |
| 
 | |
| 		/* Extended Optional Parameters Length for BGP OPEN Message */
 | |
| 		if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p))
 | |
| 			json_object_boolean_true_add(
 | |
| 				json_neigh, "extendedOptionalParametersLength");
 | |
| 		else
 | |
| 			json_object_boolean_false_add(
 | |
| 				json_neigh, "extendedOptionalParametersLength");
 | |
| 
 | |
| 		/* Conditional advertisements */
 | |
| 		json_object_int_add(
 | |
| 			json_neigh,
 | |
| 			"bgpTimerConfiguredConditionalAdvertisementsSec",
 | |
| 			bgp->condition_check_period);
 | |
| 		if (event_is_scheduled(bgp->t_condition_check))
 | |
| 			json_object_int_add(
 | |
| 				json_neigh,
 | |
| 				"bgpTimerUntilConditionalAdvertisementsSec",
 | |
| 				event_timer_remain_second(
 | |
| 					bgp->t_condition_check));
 | |
| 	} else {
 | |
| 		/* Administrative shutdown. */
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_SHUTDOWN)
 | |
| 		    || CHECK_FLAG(p->bgp->flags, BGP_FLAG_SHUTDOWN))
 | |
| 			vty_out(vty, " Administratively shut down\n");
 | |
| 
 | |
| 		/* BGP Version. */
 | |
| 		vty_out(vty, "  BGP version 4");
 | |
| 		vty_out(vty, ", remote router ID %pI4", &p->remote_id);
 | |
| 		vty_out(vty, ", local router ID %pI4\n", &bgp->router_id);
 | |
| 
 | |
| 		/* Confederation */
 | |
| 		if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
 | |
| 		    && bgp_confederation_peers_check(bgp, p->as))
 | |
| 			vty_out(vty,
 | |
| 				"  Neighbor under common administration\n");
 | |
| 
 | |
| 		/* Status. */
 | |
| 		vty_out(vty, "  BGP state = %s",
 | |
| 			lookup_msg(bgp_status_msg, p->status, NULL));
 | |
| 
 | |
| 		if (peer_established(p))
 | |
| 			vty_out(vty, ", up for %8s",
 | |
| 				peer_uptime(p->uptime, timebuf, BGP_UPTIME_LEN,
 | |
| 					    0, NULL));
 | |
| 
 | |
| 		else if (p->status == Active) {
 | |
| 			if (CHECK_FLAG(p->flags, PEER_FLAG_PASSIVE))
 | |
| 				vty_out(vty, " (passive)");
 | |
| 			else if (CHECK_FLAG(p->sflags, PEER_STATUS_NSF_WAIT))
 | |
| 				vty_out(vty, " (NSF passive)");
 | |
| 		}
 | |
| 		vty_out(vty, "\n");
 | |
| 
 | |
| 		/* read timer */
 | |
| 		vty_out(vty, "  Last read %s",
 | |
| 			peer_uptime(p->readtime, timebuf, BGP_UPTIME_LEN, 0,
 | |
| 				    NULL));
 | |
| 		vty_out(vty, ", Last write %s\n",
 | |
| 			peer_uptime(p->last_write, timebuf, BGP_UPTIME_LEN, 0,
 | |
| 				    NULL));
 | |
| 
 | |
| 		/* Configured timer values. */
 | |
| 		vty_out(vty,
 | |
| 			"  Hold time is %d seconds, keepalive interval is %d seconds\n",
 | |
| 			p->v_holdtime, p->v_keepalive);
 | |
| 		vty_out(vty, "  Configured hold time is %d seconds",
 | |
| 			CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
 | |
| 				? p->holdtime
 | |
| 				: bgp->default_holdtime);
 | |
| 		vty_out(vty, ", keepalive interval is %d seconds\n",
 | |
| 			CHECK_FLAG(p->flags, PEER_FLAG_TIMER)
 | |
| 				? p->keepalive
 | |
| 				: bgp->default_keepalive);
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER_DELAYOPEN))
 | |
| 			vty_out(vty,
 | |
| 				"  Configured DelayOpenTime is %d seconds\n",
 | |
| 				p->delayopen);
 | |
| 
 | |
| 		/* Configured and synced tcp-mss value for peer */
 | |
| 		if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) {
 | |
| 			sync_tcp_mss = sockopt_tcp_mss_get(p->fd);
 | |
| 			vty_out(vty, "  Configured tcp-mss is %d", p->tcp_mss);
 | |
| 			vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss);
 | |
| 		}
 | |
| 
 | |
| 		/* Extended Optional Parameters Length for BGP OPEN Message */
 | |
| 		if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p))
 | |
| 			vty_out(vty,
 | |
| 				"  Extended Optional Parameters Length is enabled\n");
 | |
| 
 | |
| 		/* Conditional advertisements */
 | |
| 		vty_out(vty,
 | |
| 			"  Configured conditional advertisements interval is %d seconds\n",
 | |
| 			bgp->condition_check_period);
 | |
| 		if (event_is_scheduled(bgp->t_condition_check))
 | |
| 			vty_out(vty,
 | |
| 				"  Time until conditional advertisements begin is %lu seconds\n",
 | |
| 				event_timer_remain_second(
 | |
| 					bgp->t_condition_check));
 | |
| 	}
 | |
| 	/* Capability. */
 | |
| 	if (peer_established(p) &&
 | |
| 	    (p->cap || peer_afc_advertised(p) || peer_afc_received(p))) {
 | |
| 		if (use_json) {
 | |
| 			json_object *json_cap = NULL;
 | |
| 
 | |
| 			json_cap = json_object_new_object();
 | |
| 
 | |
| 			/* AS4 */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "4byteAs",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "4byteAs",
 | |
| 							       "advertised");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "4byteAs",
 | |
| 							       "received");
 | |
| 			}
 | |
| 
 | |
| 			/* Extended Message Support */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV) &&
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV))
 | |
| 				json_object_string_add(json_cap,
 | |
| 						       "extendedMessage",
 | |
| 						       "advertisedAndReceived");
 | |
| 			else if (CHECK_FLAG(p->cap,
 | |
| 					    PEER_CAP_EXTENDED_MESSAGE_ADV))
 | |
| 				json_object_string_add(json_cap,
 | |
| 						       "extendedMessage",
 | |
| 						       "advertised");
 | |
| 			else if (CHECK_FLAG(p->cap,
 | |
| 					    PEER_CAP_EXTENDED_MESSAGE_RCV))
 | |
| 				json_object_string_add(json_cap,
 | |
| 						       "extendedMessage",
 | |
| 						       "received");
 | |
| 
 | |
| 			/* AddPath */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) {
 | |
| 				json_object *json_add = NULL;
 | |
| 				const char *print_store;
 | |
| 
 | |
| 				json_add = json_object_new_object();
 | |
| 
 | |
| 				FOREACH_AFI_SAFI (afi, safi) {
 | |
| 					json_object *json_sub = NULL;
 | |
| 					json_sub = json_object_new_object();
 | |
| 					print_store = get_afi_safi_str(
 | |
| 						afi, safi, true);
 | |
| 
 | |
| 					if (CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_RCV)) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_TX_ADV) &&
 | |
| 						    CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_TX_RCV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"txAdvertisedAndReceived");
 | |
| 						else if (
 | |
| 							CHECK_FLAG(
 | |
| 								p->af_cap[afi]
 | |
| 									 [safi],
 | |
| 								PEER_CAP_ADDPATH_AF_TX_ADV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"txAdvertised");
 | |
| 						else if (
 | |
| 							CHECK_FLAG(
 | |
| 								p->af_cap[afi]
 | |
| 									 [safi],
 | |
| 								PEER_CAP_ADDPATH_AF_TX_RCV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"txReceived");
 | |
| 					}
 | |
| 
 | |
| 					if (CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_RCV)) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_RX_ADV) &&
 | |
| 						    CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_RX_RCV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"rxAdvertisedAndReceived");
 | |
| 						else if (
 | |
| 							CHECK_FLAG(
 | |
| 								p->af_cap[afi]
 | |
| 									 [safi],
 | |
| 								PEER_CAP_ADDPATH_AF_RX_ADV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"rxAdvertised");
 | |
| 						else if (
 | |
| 							CHECK_FLAG(
 | |
| 								p->af_cap[afi]
 | |
| 									 [safi],
 | |
| 								PEER_CAP_ADDPATH_AF_RX_RCV))
 | |
| 							json_object_boolean_true_add(
 | |
| 								json_sub,
 | |
| 								"rxReceived");
 | |
| 					}
 | |
| 
 | |
| 					if (CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_RCV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_RCV))
 | |
| 						json_object_object_add(
 | |
| 							json_add, print_store,
 | |
| 							json_sub);
 | |
| 					else
 | |
| 						json_object_free(json_sub);
 | |
| 				}
 | |
| 
 | |
| 				json_object_object_add(json_cap, "addPath",
 | |
| 						       json_add);
 | |
| 			}
 | |
| 
 | |
| 			/* Dynamic */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "dynamic",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_DYNAMIC_ADV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "dynamic",
 | |
| 							       "advertised");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_DYNAMIC_RCV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "dynamic",
 | |
| 							       "received");
 | |
| 			}
 | |
| 
 | |
| 			/* Role */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ROLE_ADV)) {
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_ROLE_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "role",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_ADV))
 | |
| 					json_object_string_add(json_cap, "role",
 | |
| 							       "advertised");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_RCV))
 | |
| 					json_object_string_add(json_cap, "role",
 | |
| 							       "received");
 | |
| 			}
 | |
| 
 | |
| 			/* Extended nexthop */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
 | |
| 				json_object *json_nxt = NULL;
 | |
| 				const char *print_store;
 | |
| 
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "extendedNexthop",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "extendedNexthop",
 | |
| 						"advertised");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "extendedNexthop",
 | |
| 						"received");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) {
 | |
| 					json_nxt = json_object_new_object();
 | |
| 
 | |
| 					for (safi = SAFI_UNICAST;
 | |
| 					     safi < SAFI_MAX; safi++) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[AFI_IP]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ENHE_AF_RCV)) {
 | |
| 							print_store =
 | |
| 								get_afi_safi_str(
 | |
| 									AFI_IP,
 | |
| 									safi,
 | |
| 									true);
 | |
| 							json_object_string_add(
 | |
| 								json_nxt,
 | |
| 								print_store,
 | |
| 								"recieved"); /* misspelled for compatibility */
 | |
| 						}
 | |
| 					}
 | |
| 					json_object_object_add(
 | |
| 						json_cap,
 | |
| 						"extendedNexthopFamililesByPeer",
 | |
| 						json_nxt);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/* Long-lived Graceful Restart */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
 | |
| 				json_object *json_llgr = NULL;
 | |
| 				const char *afi_safi_str;
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"longLivedGracefulRestart",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"longLivedGracefulRestart",
 | |
| 						"advertised");
 | |
| 				else if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"longLivedGracefulRestart",
 | |
| 						"received");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)) {
 | |
| 					json_llgr = json_object_new_object();
 | |
| 
 | |
| 					FOREACH_AFI_SAFI (afi, safi) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ENHE_AF_RCV)) {
 | |
| 							afi_safi_str =
 | |
| 								get_afi_safi_str(
 | |
| 									afi,
 | |
| 									safi,
 | |
| 									true);
 | |
| 							json_object_string_add(
 | |
| 								json_llgr,
 | |
| 								afi_safi_str,
 | |
| 								"received");
 | |
| 						}
 | |
| 					}
 | |
| 					json_object_object_add(
 | |
| 						json_cap,
 | |
| 						"longLivedGracefulRestartByPeer",
 | |
| 						json_llgr);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/* Route Refresh */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_REFRESH_RCV)) {
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_REFRESH_RCV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "routeRefresh",
 | |
| 							       "advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_REFRESH_ADV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "routeRefresh",
 | |
| 							       "advertised");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_REFRESH_RCV))
 | |
| 					json_object_string_add(json_cap,
 | |
| 							       "routeRefresh",
 | |
| 							       "received");
 | |
| 			}
 | |
| 
 | |
| 			/* Enhanced Route Refresh */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) {
 | |
| 				if (CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_ENHANCED_RR_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_ENHANCED_RR_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"enhancedRouteRefresh",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_ENHANCED_RR_ADV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"enhancedRouteRefresh",
 | |
| 						"advertised");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_ENHANCED_RR_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"enhancedRouteRefresh",
 | |
| 						"received");
 | |
| 			}
 | |
| 
 | |
| 			/* Multiprotocol Extensions */
 | |
| 			json_object *json_multi = NULL;
 | |
| 
 | |
| 			json_multi = json_object_new_object();
 | |
| 
 | |
| 			FOREACH_AFI_SAFI (afi, safi) {
 | |
| 				if (p->afc_adv[afi][safi] ||
 | |
| 				    p->afc_recv[afi][safi]) {
 | |
| 					json_object *json_exten = NULL;
 | |
| 					json_exten = json_object_new_object();
 | |
| 
 | |
| 					if (p->afc_adv[afi][safi] &&
 | |
| 					    p->afc_recv[afi][safi])
 | |
| 						json_object_boolean_true_add(
 | |
| 							json_exten,
 | |
| 							"advertisedAndReceived");
 | |
| 					else if (p->afc_adv[afi][safi])
 | |
| 						json_object_boolean_true_add(
 | |
| 							json_exten,
 | |
| 							"advertised");
 | |
| 					else if (p->afc_recv[afi][safi])
 | |
| 						json_object_boolean_true_add(
 | |
| 							json_exten, "received");
 | |
| 
 | |
| 					json_object_object_add(
 | |
| 						json_multi,
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 true),
 | |
| 						json_exten);
 | |
| 				}
 | |
| 			}
 | |
| 			json_object_object_add(json_cap,
 | |
| 					       "multiprotocolExtensions",
 | |
| 					       json_multi);
 | |
| 
 | |
| 			/* Hostname capabilities */
 | |
| 			json_object *json_hname = NULL;
 | |
| 
 | |
| 			json_hname = json_object_new_object();
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
 | |
| 				json_object_string_add(
 | |
| 					json_hname, "advHostName",
 | |
| 					bgp->peer_self->hostname
 | |
| 						? bgp->peer_self->hostname
 | |
| 						: "n/a");
 | |
| 				json_object_string_add(
 | |
| 					json_hname, "advDomainName",
 | |
| 					bgp->peer_self->domainname
 | |
| 						? bgp->peer_self->domainname
 | |
| 						: "n/a");
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
 | |
| 				json_object_string_add(
 | |
| 					json_hname, "rcvHostName",
 | |
| 					p->hostname ? p->hostname : "n/a");
 | |
| 				json_object_string_add(
 | |
| 					json_hname, "rcvDomainName",
 | |
| 					p->domainname ? p->domainname : "n/a");
 | |
| 			}
 | |
| 
 | |
| 			json_object_object_add(json_cap, "hostName",
 | |
| 					       json_hname);
 | |
| 
 | |
| 			/* Software Version capability */
 | |
| 			json_object *json_soft_version = NULL;
 | |
| 
 | |
| 			json_soft_version = json_object_new_object();
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_ADV))
 | |
| 				json_object_string_add(
 | |
| 					json_soft_version,
 | |
| 					"advertisedSoftwareVersion",
 | |
| 					cmd_software_version_get());
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_RCV))
 | |
| 				json_object_string_add(
 | |
| 					json_soft_version,
 | |
| 					"receivedSoftwareVersion",
 | |
| 					p->soft_version ? p->soft_version
 | |
| 							: "n/a");
 | |
| 
 | |
| 			json_object_object_add(json_cap, "softwareVersion",
 | |
| 					       json_soft_version);
 | |
| 
 | |
| 			/* Graceful Restart */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) &&
 | |
| 				    CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap, "gracefulRestart",
 | |
| 						"advertisedAndReceived");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_RESTART_ADV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"gracefulRestartCapability",
 | |
| 						"advertised");
 | |
| 				else if (CHECK_FLAG(p->cap,
 | |
| 						    PEER_CAP_RESTART_RCV))
 | |
| 					json_object_string_add(
 | |
| 						json_cap,
 | |
| 						"gracefulRestartCapability",
 | |
| 						"received");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 					int restart_af_count = 0;
 | |
| 					json_object *json_restart = NULL;
 | |
| 					json_restart = json_object_new_object();
 | |
| 
 | |
| 					json_object_int_add(
 | |
| 						json_cap,
 | |
| 						"gracefulRestartRemoteTimerMsecs",
 | |
| 						p->v_gr_restart * 1000);
 | |
| 
 | |
| 					FOREACH_AFI_SAFI (afi, safi) {
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_RESTART_AF_RCV)) {
 | |
| 							json_object *json_sub =
 | |
| 								NULL;
 | |
| 							json_sub =
 | |
| 								json_object_new_object();
 | |
| 
 | |
| 							if (CHECK_FLAG(
 | |
| 								    p->af_cap
 | |
| 									    [afi]
 | |
| 									    [safi],
 | |
| 								    PEER_CAP_RESTART_AF_PRESERVE_RCV))
 | |
| 								json_object_boolean_true_add(
 | |
| 									json_sub,
 | |
| 									"preserved");
 | |
| 							restart_af_count++;
 | |
| 							json_object_object_add(
 | |
| 								json_restart,
 | |
| 								get_afi_safi_str(
 | |
| 									afi,
 | |
| 									safi,
 | |
| 									true),
 | |
| 								json_sub);
 | |
| 						}
 | |
| 					}
 | |
| 					if (!restart_af_count) {
 | |
| 						json_object_string_add(
 | |
| 							json_cap,
 | |
| 							"addressFamiliesByPeer",
 | |
| 							"none");
 | |
| 						json_object_free(json_restart);
 | |
| 					} else
 | |
| 						json_object_object_add(
 | |
| 							json_cap,
 | |
| 							"addressFamiliesByPeer",
 | |
| 							json_restart);
 | |
| 				}
 | |
| 			}
 | |
| 			json_object_object_add(
 | |
| 				json_neigh, "neighborCapabilities", json_cap);
 | |
| 		} else {
 | |
| 			vty_out(vty, "  Neighbor capabilities:\n");
 | |
| 
 | |
| 			/* AS4 */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
 | |
| 				vty_out(vty, "    4 Byte AS:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_AS4_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* Extended Message Support */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV)) {
 | |
| 				vty_out(vty, "    Extended Message:");
 | |
| 				if (CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_EXTENDED_MESSAGE_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_EXTENDED_MESSAGE_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(
 | |
| 							p->cap,
 | |
| 							PEER_CAP_EXTENDED_MESSAGE_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* AddPath */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) {
 | |
| 				vty_out(vty, "    AddPath:\n");
 | |
| 
 | |
| 				FOREACH_AFI_SAFI (afi, safi) {
 | |
| 					if (CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_TX_RCV)) {
 | |
| 						vty_out(vty, "      %s: TX ",
 | |
| 							get_afi_safi_str(
 | |
| 								afi, safi,
 | |
| 								false));
 | |
| 
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_TX_ADV))
 | |
| 							vty_out(vty,
 | |
| 								"advertised");
 | |
| 
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_TX_RCV))
 | |
| 							vty_out(vty,
 | |
| 								"%sreceived",
 | |
| 								CHECK_FLAG(
 | |
| 									p->af_cap
 | |
| 										[afi]
 | |
| 										[safi],
 | |
| 									PEER_CAP_ADDPATH_AF_TX_ADV)
 | |
| 									? " and "
 | |
| 									: "");
 | |
| 
 | |
| 						vty_out(vty, "\n");
 | |
| 					}
 | |
| 
 | |
| 					if (CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_ADV) ||
 | |
| 					    CHECK_FLAG(
 | |
| 						    p->af_cap[afi][safi],
 | |
| 						    PEER_CAP_ADDPATH_AF_RX_RCV)) {
 | |
| 						vty_out(vty, "      %s: RX ",
 | |
| 							get_afi_safi_str(
 | |
| 								afi, safi,
 | |
| 								false));
 | |
| 
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_RX_ADV))
 | |
| 							vty_out(vty,
 | |
| 								"advertised");
 | |
| 
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ADDPATH_AF_RX_RCV))
 | |
| 							vty_out(vty,
 | |
| 								"%sreceived",
 | |
| 								CHECK_FLAG(
 | |
| 									p->af_cap
 | |
| 										[afi]
 | |
| 										[safi],
 | |
| 									PEER_CAP_ADDPATH_AF_RX_ADV)
 | |
| 									? " and "
 | |
| 									: "");
 | |
| 
 | |
| 						vty_out(vty, "\n");
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/* Dynamic */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
 | |
| 				vty_out(vty, "    Dynamic:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_DYNAMIC_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* Role */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ROLE_ADV)) {
 | |
| 				vty_out(vty, "    Role:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ROLE_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_ROLE_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* Extended nexthop */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
 | |
| 				vty_out(vty, "    Extended nexthop:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_ENHE_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) {
 | |
| 					vty_out(vty,
 | |
| 						"      Address families by peer:\n        ");
 | |
| 					for (safi = SAFI_UNICAST;
 | |
| 					     safi < SAFI_MAX; safi++)
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[AFI_IP]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_ENHE_AF_RCV))
 | |
| 							vty_out(vty,
 | |
| 								"           %s\n",
 | |
| 								get_afi_safi_str(
 | |
| 									AFI_IP,
 | |
| 									safi,
 | |
| 									false));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/* Long-lived Graceful Restart */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
 | |
| 				vty_out(vty,
 | |
| 					"    Long-lived Graceful Restart:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_LLGR_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)) {
 | |
| 					vty_out(vty,
 | |
| 						"      Address families by peer:\n");
 | |
| 					FOREACH_AFI_SAFI (afi, safi)
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_LLGR_AF_RCV))
 | |
| 							vty_out(vty,
 | |
| 								"           %s\n",
 | |
| 								get_afi_safi_str(
 | |
| 									afi,
 | |
| 									safi,
 | |
| 									false));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/* Route Refresh */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_REFRESH_RCV)) {
 | |
| 				vty_out(vty, "    Route refresh:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_REFRESH_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* Enhanced Route Refresh */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) {
 | |
| 				vty_out(vty, "    Enhanced Route Refresh:");
 | |
| 				if (CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_ENHANCED_RR_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap,
 | |
| 					       PEER_CAP_ENHANCED_RR_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_REFRESH_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 
 | |
| 			/* Multiprotocol Extensions */
 | |
| 			FOREACH_AFI_SAFI (afi, safi)
 | |
| 				if (p->afc_adv[afi][safi] ||
 | |
| 				    p->afc_recv[afi][safi]) {
 | |
| 					vty_out(vty, "    Address Family %s:",
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 false));
 | |
| 					if (p->afc_adv[afi][safi])
 | |
| 						vty_out(vty, " advertised");
 | |
| 					if (p->afc_recv[afi][safi])
 | |
| 						vty_out(vty, " %sreceived",
 | |
| 							p->afc_adv[afi][safi]
 | |
| 								? "and "
 | |
| 								: "");
 | |
| 					vty_out(vty, "\n");
 | |
| 				}
 | |
| 
 | |
| 			/* Hostname capability */
 | |
| 			vty_out(vty, "    Hostname Capability:");
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
 | |
| 				vty_out(vty,
 | |
| 					" advertised (name: %s,domain name: %s)",
 | |
| 					bgp->peer_self->hostname
 | |
| 						? bgp->peer_self->hostname
 | |
| 						: "n/a",
 | |
| 					bgp->peer_self->domainname
 | |
| 						? bgp->peer_self->domainname
 | |
| 						: "n/a");
 | |
| 			} else {
 | |
| 				vty_out(vty, " not advertised");
 | |
| 			}
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
 | |
| 				vty_out(vty,
 | |
| 					" received (name: %s,domain name: %s)",
 | |
| 					p->hostname ? p->hostname : "n/a",
 | |
| 					p->domainname ? p->domainname : "n/a");
 | |
| 			} else {
 | |
| 				vty_out(vty, " not received");
 | |
| 			}
 | |
| 
 | |
| 			vty_out(vty, "\n");
 | |
| 
 | |
| 			/* Software Version capability */
 | |
| 			vty_out(vty, "    Version Capability:");
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_ADV)) {
 | |
| 				vty_out(vty,
 | |
| 					" advertised software version (%s)",
 | |
| 					cmd_software_version_get());
 | |
| 			} else
 | |
| 				vty_out(vty, " not advertised");
 | |
| 
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_RCV)) {
 | |
| 				vty_out(vty, " received software version (%s)",
 | |
| 					p->soft_version ? p->soft_version
 | |
| 							: "n/a");
 | |
| 			} else
 | |
| 				vty_out(vty, " not received");
 | |
| 
 | |
| 			vty_out(vty, "\n");
 | |
| 
 | |
| 			/* Graceful Restart */
 | |
| 			if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
 | |
| 			    CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
 | |
| 				vty_out(vty,
 | |
| 					"    Graceful Restart Capability:");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV))
 | |
| 					vty_out(vty, " advertised");
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
 | |
| 					vty_out(vty, " %sreceived",
 | |
| 						CHECK_FLAG(p->cap,
 | |
| 							   PEER_CAP_RESTART_ADV)
 | |
| 							? "and "
 | |
| 							: "");
 | |
| 				vty_out(vty, "\n");
 | |
| 
 | |
| 				if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 					int restart_af_count = 0;
 | |
| 
 | |
| 					vty_out(vty,
 | |
| 						"      Remote Restart timer is %d seconds\n",
 | |
| 						p->v_gr_restart);
 | |
| 					vty_out(vty,
 | |
| 						"      Address families by peer:\n        ");
 | |
| 
 | |
| 					FOREACH_AFI_SAFI (afi, safi)
 | |
| 						if (CHECK_FLAG(
 | |
| 							    p->af_cap[afi]
 | |
| 								     [safi],
 | |
| 							    PEER_CAP_RESTART_AF_RCV)) {
 | |
| 							vty_out(vty, "%s%s(%s)",
 | |
| 								restart_af_count
 | |
| 									? ", "
 | |
| 									: "",
 | |
| 								get_afi_safi_str(
 | |
| 									afi,
 | |
| 									safi,
 | |
| 									false),
 | |
| 								CHECK_FLAG(
 | |
| 									p->af_cap
 | |
| 										[afi]
 | |
| 										[safi],
 | |
| 									PEER_CAP_RESTART_AF_PRESERVE_RCV)
 | |
| 									? "preserved"
 | |
| 									: "not preserved");
 | |
| 							restart_af_count++;
 | |
| 						}
 | |
| 					if (!restart_af_count)
 | |
| 						vty_out(vty, "none");
 | |
| 					vty_out(vty, "\n");
 | |
| 				}
 | |
| 			} /* Graceful Restart */
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* graceful restart information */
 | |
| 	json_object *json_grace = NULL;
 | |
| 	json_object *json_grace_send = NULL;
 | |
| 	json_object *json_grace_recv = NULL;
 | |
| 	int eor_send_af_count = 0;
 | |
| 	int eor_receive_af_count = 0;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_grace = json_object_new_object();
 | |
| 		json_grace_send = json_object_new_object();
 | |
| 		json_grace_recv = json_object_new_object();
 | |
| 
 | |
| 		if ((peer_established(p)) &&
 | |
| 		    CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 			FOREACH_AFI_SAFI (afi, safi) {
 | |
| 				if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 					       PEER_STATUS_EOR_SEND)) {
 | |
| 					json_object_boolean_true_add(
 | |
| 						json_grace_send,
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 true));
 | |
| 					eor_send_af_count++;
 | |
| 				}
 | |
| 			}
 | |
| 			FOREACH_AFI_SAFI (afi, safi) {
 | |
| 				if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 					       PEER_STATUS_EOR_RECEIVED)) {
 | |
| 					json_object_boolean_true_add(
 | |
| 						json_grace_recv,
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 true));
 | |
| 					eor_receive_af_count++;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		json_object_object_add(json_grace, "endOfRibSend",
 | |
| 				       json_grace_send);
 | |
| 		json_object_object_add(json_grace, "endOfRibRecv",
 | |
| 				       json_grace_recv);
 | |
| 
 | |
| 
 | |
| 		if (p->t_gr_restart)
 | |
| 			json_object_int_add(
 | |
| 				json_grace, "gracefulRestartTimerMsecs",
 | |
| 				event_timer_remain_second(p->t_gr_restart) *
 | |
| 					1000);
 | |
| 
 | |
| 		if (p->t_gr_stale)
 | |
| 			json_object_int_add(
 | |
| 				json_grace, "gracefulStalepathTimerMsecs",
 | |
| 				event_timer_remain_second(p->t_gr_stale) *
 | |
| 					1000);
 | |
| 		/* more gr info in new format */
 | |
| 		BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json_grace);
 | |
| 		json_object_object_add(json_neigh, "gracefulRestartInfo",
 | |
| 				       json_grace);
 | |
| 	} else {
 | |
| 		vty_out(vty, "  Graceful restart information:\n");
 | |
| 		if ((peer_established(p)) &&
 | |
| 		    CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
 | |
| 
 | |
| 			vty_out(vty, "    End-of-RIB send: ");
 | |
| 			FOREACH_AFI_SAFI (afi, safi) {
 | |
| 				if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 					       PEER_STATUS_EOR_SEND)) {
 | |
| 					vty_out(vty, "%s%s",
 | |
| 						eor_send_af_count ? ", " : "",
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 false));
 | |
| 					eor_send_af_count++;
 | |
| 				}
 | |
| 			}
 | |
| 			vty_out(vty, "\n");
 | |
| 			vty_out(vty, "    End-of-RIB received: ");
 | |
| 			FOREACH_AFI_SAFI (afi, safi) {
 | |
| 				if (CHECK_FLAG(p->af_sflags[afi][safi],
 | |
| 					       PEER_STATUS_EOR_RECEIVED)) {
 | |
| 					vty_out(vty, "%s%s",
 | |
| 						eor_receive_af_count ? ", "
 | |
| 								     : "",
 | |
| 						get_afi_safi_str(afi, safi,
 | |
| 								 false));
 | |
| 					eor_receive_af_count++;
 | |
| 				}
 | |
| 			}
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		if (p->t_gr_restart)
 | |
| 			vty_out(vty,
 | |
| 				"    The remaining time of restart timer is %ld\n",
 | |
| 				event_timer_remain_second(p->t_gr_restart));
 | |
| 
 | |
| 		if (p->t_gr_stale)
 | |
| 			vty_out(vty,
 | |
| 				"    The remaining time of stalepath timer is %ld\n",
 | |
| 				event_timer_remain_second(p->t_gr_stale));
 | |
| 
 | |
| 		/* more gr info in new format */
 | |
| 		BGP_SHOW_PEER_GR_CAPABILITY(vty, p, NULL);
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_object *json_stat = NULL;
 | |
| 		json_stat = json_object_new_object();
 | |
| 		/* Packet counts. */
 | |
| 
 | |
| 		atomic_size_t outq_count, inq_count;
 | |
| 		outq_count = atomic_load_explicit(&p->obuf->count,
 | |
| 						  memory_order_relaxed);
 | |
| 		inq_count = atomic_load_explicit(&p->ibuf->count,
 | |
| 						 memory_order_relaxed);
 | |
| 
 | |
| 		json_object_int_add(json_stat, "depthInq",
 | |
| 				    (unsigned long)inq_count);
 | |
| 		json_object_int_add(json_stat, "depthOutq",
 | |
| 				    (unsigned long)outq_count);
 | |
| 		json_object_int_add(json_stat, "opensSent",
 | |
| 				    atomic_load_explicit(&p->open_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "opensRecv",
 | |
| 				    atomic_load_explicit(&p->open_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "notificationsSent",
 | |
| 				    atomic_load_explicit(&p->notify_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "notificationsRecv",
 | |
| 				    atomic_load_explicit(&p->notify_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "updatesSent",
 | |
| 				    atomic_load_explicit(&p->update_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "updatesRecv",
 | |
| 				    atomic_load_explicit(&p->update_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "keepalivesSent",
 | |
| 				    atomic_load_explicit(&p->keepalive_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "keepalivesRecv",
 | |
| 				    atomic_load_explicit(&p->keepalive_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "routeRefreshSent",
 | |
| 				    atomic_load_explicit(&p->refresh_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "routeRefreshRecv",
 | |
| 				    atomic_load_explicit(&p->refresh_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "capabilitySent",
 | |
| 				    atomic_load_explicit(&p->dynamic_cap_out,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "capabilityRecv",
 | |
| 				    atomic_load_explicit(&p->dynamic_cap_in,
 | |
| 							 memory_order_relaxed));
 | |
| 		json_object_int_add(json_stat, "totalSent", PEER_TOTAL_TX(p));
 | |
| 		json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p));
 | |
| 		json_object_object_add(json_neigh, "messageStats", json_stat);
 | |
| 	} else {
 | |
| 		atomic_size_t outq_count, inq_count, open_out, open_in,
 | |
| 			notify_out, notify_in, update_out, update_in,
 | |
| 			keepalive_out, keepalive_in, refresh_out, refresh_in,
 | |
| 			dynamic_cap_out, dynamic_cap_in;
 | |
| 		outq_count = atomic_load_explicit(&p->obuf->count,
 | |
| 						  memory_order_relaxed);
 | |
| 		inq_count = atomic_load_explicit(&p->ibuf->count,
 | |
| 						 memory_order_relaxed);
 | |
| 		open_out = atomic_load_explicit(&p->open_out,
 | |
| 						memory_order_relaxed);
 | |
| 		open_in =
 | |
| 			atomic_load_explicit(&p->open_in, memory_order_relaxed);
 | |
| 		notify_out = atomic_load_explicit(&p->notify_out,
 | |
| 						  memory_order_relaxed);
 | |
| 		notify_in = atomic_load_explicit(&p->notify_in,
 | |
| 						 memory_order_relaxed);
 | |
| 		update_out = atomic_load_explicit(&p->update_out,
 | |
| 						  memory_order_relaxed);
 | |
| 		update_in = atomic_load_explicit(&p->update_in,
 | |
| 						 memory_order_relaxed);
 | |
| 		keepalive_out = atomic_load_explicit(&p->keepalive_out,
 | |
| 						     memory_order_relaxed);
 | |
| 		keepalive_in = atomic_load_explicit(&p->keepalive_in,
 | |
| 						    memory_order_relaxed);
 | |
| 		refresh_out = atomic_load_explicit(&p->refresh_out,
 | |
| 						   memory_order_relaxed);
 | |
| 		refresh_in = atomic_load_explicit(&p->refresh_in,
 | |
| 						  memory_order_relaxed);
 | |
| 		dynamic_cap_out = atomic_load_explicit(&p->dynamic_cap_out,
 | |
| 						       memory_order_relaxed);
 | |
| 		dynamic_cap_in = atomic_load_explicit(&p->dynamic_cap_in,
 | |
| 						      memory_order_relaxed);
 | |
| 
 | |
| 		/* Packet counts. */
 | |
| 		vty_out(vty, "  Message statistics:\n");
 | |
| 		vty_out(vty, "    Inq depth is %zu\n", inq_count);
 | |
| 		vty_out(vty, "    Outq depth is %zu\n", outq_count);
 | |
| 		vty_out(vty, "                         Sent       Rcvd\n");
 | |
| 		vty_out(vty, "    Opens:         %10zu %10zu\n", open_out,
 | |
| 			open_in);
 | |
| 		vty_out(vty, "    Notifications: %10zu %10zu\n", notify_out,
 | |
| 			notify_in);
 | |
| 		vty_out(vty, "    Updates:       %10zu %10zu\n", update_out,
 | |
| 			update_in);
 | |
| 		vty_out(vty, "    Keepalives:    %10zu %10zu\n", keepalive_out,
 | |
| 			keepalive_in);
 | |
| 		vty_out(vty, "    Route Refresh: %10zu %10zu\n", refresh_out,
 | |
| 			refresh_in);
 | |
| 		vty_out(vty, "    Capability:    %10zu %10zu\n",
 | |
| 			dynamic_cap_out, dynamic_cap_in);
 | |
| 		vty_out(vty, "    Total:         %10u %10u\n",
 | |
| 			(uint32_t)PEER_TOTAL_TX(p), (uint32_t)PEER_TOTAL_RX(p));
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		/* advertisement-interval */
 | |
| 		json_object_int_add(json_neigh,
 | |
| 				    "minBtwnAdvertisementRunsTimerMsecs",
 | |
| 				    p->v_routeadv * 1000);
 | |
| 
 | |
| 		/* Update-source. */
 | |
| 		if (p->update_if || p->update_source) {
 | |
| 			if (p->update_if)
 | |
| 				json_object_string_add(json_neigh,
 | |
| 						       "updateSource",
 | |
| 						       p->update_if);
 | |
| 			else if (p->update_source)
 | |
| 				json_object_string_addf(json_neigh,
 | |
| 							"updateSource", "%pSU",
 | |
| 							p->update_source);
 | |
| 		}
 | |
| 	} else {
 | |
| 		/* advertisement-interval */
 | |
| 		vty_out(vty,
 | |
| 			"  Minimum time between advertisement runs is %d seconds\n",
 | |
| 			p->v_routeadv);
 | |
| 
 | |
| 		/* Update-source. */
 | |
| 		if (p->update_if || p->update_source) {
 | |
| 			vty_out(vty, "  Update source is ");
 | |
| 			if (p->update_if)
 | |
| 				vty_out(vty, "%s", p->update_if);
 | |
| 			else if (p->update_source)
 | |
| 				vty_out(vty, "%pSU", p->update_source);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Address Family Information */
 | |
| 	json_object *json_hold = NULL;
 | |
| 
 | |
| 	if (use_json)
 | |
| 		json_hold = json_object_new_object();
 | |
| 
 | |
| 	FOREACH_AFI_SAFI (afi, safi)
 | |
| 		if (p->afc[afi][safi])
 | |
| 			bgp_show_peer_afi(vty, p, afi, safi, use_json,
 | |
| 					  json_hold);
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_object_object_add(json_neigh, "addressFamilyInfo",
 | |
| 				       json_hold);
 | |
| 		json_object_int_add(json_neigh, "connectionsEstablished",
 | |
| 				    p->established);
 | |
| 		json_object_int_add(json_neigh, "connectionsDropped",
 | |
| 				    p->dropped);
 | |
| 	} else
 | |
| 		vty_out(vty, "  Connections established %d; dropped %d\n",
 | |
| 			p->established, p->dropped);
 | |
| 
 | |
| 	if (!p->last_reset) {
 | |
| 		if (use_json)
 | |
| 			json_object_string_add(json_neigh, "lastReset",
 | |
| 					       "never");
 | |
| 		else
 | |
| 			vty_out(vty, "  Last reset never\n");
 | |
| 	} else {
 | |
| 		if (use_json) {
 | |
| 			time_t uptime;
 | |
| 			struct tm tm;
 | |
| 
 | |
| 			uptime = monotime(NULL);
 | |
| 			uptime -= p->resettime;
 | |
| 			gmtime_r(&uptime, &tm);
 | |
| 
 | |
| 			json_object_int_add(json_neigh, "lastResetTimerMsecs",
 | |
| 					    (tm.tm_sec * 1000)
 | |
| 						    + (tm.tm_min * 60000)
 | |
| 						    + (tm.tm_hour * 3600000));
 | |
| 			bgp_show_peer_reset(NULL, p, json_neigh, true);
 | |
| 		} else {
 | |
| 			vty_out(vty, "  Last reset %s, ",
 | |
| 				peer_uptime(p->resettime, timebuf,
 | |
| 					    BGP_UPTIME_LEN, 0, NULL));
 | |
| 
 | |
| 			bgp_show_peer_reset(vty, p, NULL, false);
 | |
| 			if (p->last_reset_cause_size) {
 | |
| 				msg = p->last_reset_cause;
 | |
| 				vty_out(vty,
 | |
| 					"  Message received that caused BGP to send a NOTIFICATION:\n    ");
 | |
| 				for (i = 1; i <= p->last_reset_cause_size;
 | |
| 				     i++) {
 | |
| 					vty_out(vty, "%02X", *msg++);
 | |
| 
 | |
| 					if (i != p->last_reset_cause_size) {
 | |
| 						if (i % 16 == 0) {
 | |
| 							vty_out(vty, "\n    ");
 | |
| 						} else if (i % 4 == 0) {
 | |
| 							vty_out(vty, " ");
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(p->sflags, PEER_STATUS_PREFIX_OVERFLOW)) {
 | |
| 		if (use_json)
 | |
| 			json_object_boolean_true_add(json_neigh,
 | |
| 						     "prefixesConfigExceedMax");
 | |
| 		else
 | |
| 			vty_out(vty,
 | |
| 				"  Peer had exceeded the max. no. of prefixes configured.\n");
 | |
| 
 | |
| 		if (p->t_pmax_restart) {
 | |
| 			if (use_json) {
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_neigh, "reducePrefixNumFrom");
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "restartInTimerMsec",
 | |
| 						    event_timer_remain_second(
 | |
| 							    p->t_pmax_restart) *
 | |
| 							    1000);
 | |
| 			} else
 | |
| 				vty_out(vty,
 | |
| 					"  Reduce the no. of prefix from %s, will restart in %ld seconds\n",
 | |
| 					p->host,
 | |
| 					event_timer_remain_second(
 | |
| 						p->t_pmax_restart));
 | |
| 		} else {
 | |
| 			if (use_json)
 | |
| 				json_object_boolean_true_add(
 | |
| 					json_neigh,
 | |
| 					"reducePrefixNumAndClearIpBgp");
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"  Reduce the no. of prefix and clear ip bgp %s to restore peering\n",
 | |
| 					p->host);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* EBGP Multihop and GTSM */
 | |
| 	if (p->sort != BGP_PEER_IBGP) {
 | |
| 		if (use_json) {
 | |
| 			if (p->gtsm_hops > BGP_GTSM_HOPS_DISABLED)
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "externalBgpNbrMaxHopsAway",
 | |
| 						    p->gtsm_hops);
 | |
| 			else
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "externalBgpNbrMaxHopsAway",
 | |
| 						    p->ttl);
 | |
| 		} else {
 | |
| 			if (p->gtsm_hops > BGP_GTSM_HOPS_DISABLED)
 | |
| 				vty_out(vty,
 | |
| 					"  External BGP neighbor may be up to %d hops away.\n",
 | |
| 					p->gtsm_hops);
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"  External BGP neighbor may be up to %d hops away.\n",
 | |
| 					p->ttl);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (use_json) {
 | |
| 			if (p->gtsm_hops > BGP_GTSM_HOPS_DISABLED)
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "internalBgpNbrMaxHopsAway",
 | |
| 						    p->gtsm_hops);
 | |
| 			else
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "internalBgpNbrMaxHopsAway",
 | |
| 						    p->ttl);
 | |
| 		} else {
 | |
| 			if (p->gtsm_hops > BGP_GTSM_HOPS_DISABLED)
 | |
| 				vty_out(vty,
 | |
| 					"  Internal BGP neighbor may be up to %d hops away.\n",
 | |
| 					p->gtsm_hops);
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"  Internal BGP neighbor may be up to %d hops away.\n",
 | |
| 					p->ttl);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Local address. */
 | |
| 	if (p->su_local) {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_addf(json_neigh, "hostLocal", "%pSU",
 | |
| 						p->su_local);
 | |
| 			json_object_int_add(json_neigh, "portLocal",
 | |
| 					    ntohs(p->su_local->sin.sin_port));
 | |
| 		} else
 | |
| 			vty_out(vty, "Local host: %pSU, Local port: %d\n",
 | |
| 				p->su_local, ntohs(p->su_local->sin.sin_port));
 | |
| 	} else {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_add(json_neigh, "hostLocal",
 | |
| 					       "Unknown");
 | |
| 			json_object_int_add(json_neigh, "portLocal", -1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Remote address. */
 | |
| 	if (p->su_remote) {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_addf(json_neigh, "hostForeign",
 | |
| 						"%pSU", p->su_remote);
 | |
| 			json_object_int_add(json_neigh, "portForeign",
 | |
| 					    ntohs(p->su_remote->sin.sin_port));
 | |
| 		} else
 | |
| 			vty_out(vty, "Foreign host: %pSU, Foreign port: %d\n",
 | |
| 				p->su_remote,
 | |
| 				ntohs(p->su_remote->sin.sin_port));
 | |
| 	} else {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_add(json_neigh, "hostForeign",
 | |
| 					       "Unknown");
 | |
| 			json_object_int_add(json_neigh, "portForeign", -1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Nexthop display. */
 | |
| 	if (p->su_local) {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_addf(json_neigh, "nexthop", "%pI4",
 | |
| 						&p->nexthop.v4);
 | |
| 			json_object_string_addf(json_neigh, "nexthopGlobal",
 | |
| 						"%pI6", &p->nexthop.v6_global);
 | |
| 			json_object_string_addf(json_neigh, "nexthopLocal",
 | |
| 						"%pI6", &p->nexthop.v6_local);
 | |
| 			if (p->shared_network)
 | |
| 				json_object_string_add(json_neigh,
 | |
| 						       "bgpConnection",
 | |
| 						       "sharedNetwork");
 | |
| 			else
 | |
| 				json_object_string_add(json_neigh,
 | |
| 						       "bgpConnection",
 | |
| 						       "nonSharedNetwork");
 | |
| 		} else {
 | |
| 			vty_out(vty, "Nexthop: %pI4\n", &p->nexthop.v4);
 | |
| 			vty_out(vty, "Nexthop global: %pI6\n",
 | |
| 				&p->nexthop.v6_global);
 | |
| 			vty_out(vty, "Nexthop local: %pI6\n",
 | |
| 				&p->nexthop.v6_local);
 | |
| 			vty_out(vty, "BGP connection: %s\n",
 | |
| 				p->shared_network ? "shared network"
 | |
| 						  : "non shared network");
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (use_json) {
 | |
| 			json_object_string_add(json_neigh, "nexthop",
 | |
| 					       "Unknown");
 | |
| 			json_object_string_add(json_neigh, "nexthopGlobal",
 | |
| 					       "Unknown");
 | |
| 			json_object_string_add(json_neigh, "nexthopLocal",
 | |
| 					       "Unknown");
 | |
| 			json_object_string_add(json_neigh, "bgpConnection",
 | |
| 					       "Unknown");
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Timer information. */
 | |
| 	if (use_json) {
 | |
| 		json_object_int_add(json_neigh, "connectRetryTimer",
 | |
| 				    p->v_connect);
 | |
| 		if (peer_established(p)) {
 | |
| 			json_object_int_add(json_neigh, "estimatedRttInMsecs",
 | |
| 					    p->rtt);
 | |
| 			if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) {
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "shutdownRttInMsecs",
 | |
| 						    p->rtt_expected);
 | |
| 				json_object_int_add(json_neigh,
 | |
| 						    "shutdownRttAfterCount",
 | |
| 						    p->rtt_keepalive_rcv);
 | |
| 			}
 | |
| 		}
 | |
| 		if (p->t_start)
 | |
| 			json_object_int_add(
 | |
| 				json_neigh, "nextStartTimerDueInMsecs",
 | |
| 				event_timer_remain_second(p->t_start) * 1000);
 | |
| 		if (p->t_connect)
 | |
| 			json_object_int_add(
 | |
| 				json_neigh, "nextConnectTimerDueInMsecs",
 | |
| 				event_timer_remain_second(p->t_connect) * 1000);
 | |
| 		if (p->t_routeadv) {
 | |
| 			json_object_int_add(json_neigh, "mraiInterval",
 | |
| 					    p->v_routeadv);
 | |
| 			json_object_int_add(
 | |
| 				json_neigh, "mraiTimerExpireInMsecs",
 | |
| 				event_timer_remain_second(p->t_routeadv) *
 | |
| 					1000);
 | |
| 		}
 | |
| 		if (p->password)
 | |
| 			json_object_int_add(json_neigh, "authenticationEnabled",
 | |
| 					    1);
 | |
| 
 | |
| 		if (p->t_read)
 | |
| 			json_object_string_add(json_neigh, "readThread", "on");
 | |
| 		else
 | |
| 			json_object_string_add(json_neigh, "readThread", "off");
 | |
| 
 | |
| 		if (CHECK_FLAG(p->thread_flags, PEER_THREAD_WRITES_ON))
 | |
| 			json_object_string_add(json_neigh, "writeThread", "on");
 | |
| 		else
 | |
| 			json_object_string_add(json_neigh, "writeThread",
 | |
| 					       "off");
 | |
| 	} else {
 | |
| 		vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n",
 | |
| 			p->v_connect);
 | |
| 		if (peer_established(p)) {
 | |
| 			vty_out(vty, "Estimated round trip time: %d ms\n",
 | |
| 				p->rtt);
 | |
| 			if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN))
 | |
| 				vty_out(vty,
 | |
| 					"Shutdown when RTT > %dms, count > %u\n",
 | |
| 					p->rtt_expected, p->rtt_keepalive_rcv);
 | |
| 		}
 | |
| 		if (p->t_start)
 | |
| 			vty_out(vty, "Next start timer due in %ld seconds\n",
 | |
| 				event_timer_remain_second(p->t_start));
 | |
| 		if (p->t_connect)
 | |
| 			vty_out(vty, "Next connect timer due in %ld seconds\n",
 | |
| 				event_timer_remain_second(p->t_connect));
 | |
| 		if (p->t_routeadv)
 | |
| 			vty_out(vty,
 | |
| 				"MRAI (interval %u) timer expires in %ld seconds\n",
 | |
| 				p->v_routeadv,
 | |
| 				event_timer_remain_second(p->t_routeadv));
 | |
| 		if (p->password)
 | |
| 			vty_out(vty, "Peer Authentication Enabled\n");
 | |
| 
 | |
| 		vty_out(vty, "Read thread: %s  Write thread: %s  FD used: %d\n",
 | |
| 			p->t_read ? "on" : "off",
 | |
| 			CHECK_FLAG(p->thread_flags, PEER_THREAD_WRITES_ON)
 | |
| 				? "on"
 | |
| 				: "off", p->fd);
 | |
| 	}
 | |
| 
 | |
| 	if (p->notify.code == BGP_NOTIFY_OPEN_ERR
 | |
| 	    && p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL)
 | |
| 		bgp_capability_vty_out(vty, p, use_json, json_neigh);
 | |
| 
 | |
| 	if (!use_json)
 | |
| 		vty_out(vty, "\n");
 | |
| 
 | |
| 	/* BFD information. */
 | |
| 	if (p->bfd_config)
 | |
| 		bgp_bfd_show_info(vty, p, json_neigh);
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		if (p->conf_if) /* Configured interface name. */
 | |
| 			json_object_object_add(json, p->conf_if, json_neigh);
 | |
| 		else /* Configured IP address. */
 | |
| 			json_object_object_add(json, p->host, json_neigh);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
 | |
| 					      enum show_type type,
 | |
| 					      union sockunion *su,
 | |
| 					      const char *conf_if, afi_t afi,
 | |
| 					      json_object *json)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct peer *peer;
 | |
| 	bool found = false;
 | |
| 	safi_t safi = SAFI_UNICAST;
 | |
| 	json_object *json_neighbor = NULL;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 
 | |
| 		if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 			continue;
 | |
| 
 | |
| 		if ((peer->afc[afi][safi]) == 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (json)
 | |
| 			json_neighbor = json_object_new_object();
 | |
| 
 | |
| 		if (type == show_all) {
 | |
| 			bgp_show_peer_gr_status(vty, peer, json_neighbor);
 | |
| 
 | |
| 			if (json)
 | |
| 				json_object_object_add(json, peer->host,
 | |
| 						       json_neighbor);
 | |
| 
 | |
| 		} else if (type == show_peer) {
 | |
| 			if (conf_if) {
 | |
| 				if ((peer->conf_if
 | |
| 				     && !strcmp(peer->conf_if, conf_if))
 | |
| 				    || (peer->hostname
 | |
| 					&& !strcmp(peer->hostname, conf_if))) {
 | |
| 					found = true;
 | |
| 					bgp_show_peer_gr_status(vty, peer,
 | |
| 								json_neighbor);
 | |
| 				}
 | |
| 			} else {
 | |
| 				if (sockunion_same(&peer->su, su)) {
 | |
| 					found = true;
 | |
| 					bgp_show_peer_gr_status(vty, peer,
 | |
| 								json_neighbor);
 | |
| 				}
 | |
| 			}
 | |
| 			if (json) {
 | |
| 				if (found)
 | |
| 					json_object_object_add(json, peer->host,
 | |
| 							       json_neighbor);
 | |
| 				else
 | |
| 					json_object_free(json_neighbor);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (found)
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	if (type == show_peer && !found) {
 | |
| 		if (json)
 | |
| 			json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
 | |
| 		else
 | |
| 			vty_out(vty, "%% No such neighbor\n");
 | |
| 	}
 | |
| 
 | |
| 	if (!json)
 | |
| 		vty_out(vty, "\n");
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
 | |
| 			     enum show_type type, union sockunion *su,
 | |
| 			     const char *conf_if, bool use_json,
 | |
| 			     json_object *json)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct peer *peer;
 | |
| 	int find = 0;
 | |
| 	bool nbr_output = false;
 | |
| 	afi_t afi = AFI_MAX;
 | |
| 	safi_t safi = SAFI_MAX;
 | |
| 
 | |
| 	if (type == show_ipv4_peer || type == show_ipv4_all) {
 | |
| 		afi = AFI_IP;
 | |
| 	} else if (type == show_ipv6_peer || type == show_ipv6_all) {
 | |
| 		afi = AFI_IP6;
 | |
| 	}
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 		if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 			continue;
 | |
| 
 | |
| 		switch (type) {
 | |
| 		case show_all:
 | |
| 			bgp_show_peer(vty, peer, use_json, json);
 | |
| 			nbr_output = true;
 | |
| 			break;
 | |
| 		case show_peer:
 | |
| 			if (conf_if) {
 | |
| 				if ((peer->conf_if
 | |
| 				     && !strcmp(peer->conf_if, conf_if))
 | |
| 				    || (peer->hostname
 | |
| 					&& !strcmp(peer->hostname, conf_if))) {
 | |
| 					find = 1;
 | |
| 					bgp_show_peer(vty, peer, use_json,
 | |
| 						      json);
 | |
| 				}
 | |
| 			} else {
 | |
| 				if (sockunion_same(&peer->su, su)) {
 | |
| 					find = 1;
 | |
| 					bgp_show_peer(vty, peer, use_json,
 | |
| 						      json);
 | |
| 				}
 | |
| 			}
 | |
| 			break;
 | |
| 		case show_ipv4_peer:
 | |
| 		case show_ipv6_peer:
 | |
| 			FOREACH_SAFI (safi) {
 | |
| 				if (peer->afc[afi][safi]) {
 | |
| 					if (conf_if) {
 | |
| 						if ((peer->conf_if
 | |
| 						     && !strcmp(peer->conf_if, conf_if))
 | |
| 						    || (peer->hostname
 | |
| 							&& !strcmp(peer->hostname, conf_if))) {
 | |
| 							find = 1;
 | |
| 							bgp_show_peer(vty, peer, use_json,
 | |
| 								      json);
 | |
| 							break;
 | |
| 						}
 | |
| 					} else {
 | |
| 						if (sockunion_same(&peer->su, su)) {
 | |
| 							find = 1;
 | |
| 							bgp_show_peer(vty, peer, use_json,
 | |
| 								      json);
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			break;
 | |
| 		case show_ipv4_all:
 | |
| 		case show_ipv6_all:
 | |
| 			FOREACH_SAFI (safi) {
 | |
| 				if (peer->afc[afi][safi]) {
 | |
| 					bgp_show_peer(vty, peer, use_json, json);
 | |
| 					nbr_output = true;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ((type == show_peer || type == show_ipv4_peer ||
 | |
| 	     type == show_ipv6_peer) && !find) {
 | |
| 		if (use_json)
 | |
| 			json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
 | |
| 		else
 | |
| 			vty_out(vty, "%% No such neighbor in this view/vrf\n");
 | |
| 	}
 | |
| 
 | |
| 	if (type != show_peer && type != show_ipv4_peer &&
 | |
| 	    type != show_ipv6_peer && !nbr_output && !use_json)
 | |
| 		vty_out(vty, "%% No BGP neighbors found\n");
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		vty_out(vty, "%s\n", json_object_to_json_string_ext(
 | |
| 					     json, JSON_C_TO_STRING_PRETTY));
 | |
| 	} else {
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
 | |
| 						   enum show_type type,
 | |
| 						   const char *ip_str,
 | |
| 						   afi_t afi, json_object *json)
 | |
| {
 | |
| 
 | |
| 	int ret;
 | |
| 	struct bgp *bgp;
 | |
| 	union sockunion su;
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 
 | |
| 	if (!bgp)
 | |
| 		return;
 | |
| 
 | |
| 	if (!json)
 | |
| 		bgp_show_global_graceful_restart_mode_vty(vty, bgp);
 | |
| 
 | |
| 	if (ip_str) {
 | |
| 		ret = str2sockunion(ip_str, &su);
 | |
| 		if (ret < 0)
 | |
| 			bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL,
 | |
| 							   ip_str, afi, json);
 | |
| 		else
 | |
| 			bgp_show_neighbor_graceful_restart(vty, bgp, type, &su,
 | |
| 							   NULL, afi, json);
 | |
| 	} else
 | |
| 		bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL, NULL,
 | |
| 						   afi, json);
 | |
| }
 | |
| 
 | |
| static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
 | |
| 						 enum show_type type,
 | |
| 						 const char *ip_str,
 | |
| 						 bool use_json)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 	union sockunion su;
 | |
| 	json_object *json = NULL;
 | |
| 	int ret, is_first = 1;
 | |
| 	bool nbr_output = false;
 | |
| 
 | |
| 	if (use_json)
 | |
| 		vty_out(vty, "{\n");
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		nbr_output = true;
 | |
| 		if (use_json) {
 | |
| 			if (!(json = json_object_new_object())) {
 | |
| 				flog_err(
 | |
| 					EC_BGP_JSON_MEM_ERROR,
 | |
| 					"Unable to allocate memory for JSON object");
 | |
| 				vty_out(vty,
 | |
| 					"{\"error\": {\"message:\": \"Unable to allocate memory for JSON object\"}}}\n");
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			json_object_int_add(json, "vrfId",
 | |
| 					    (bgp->vrf_id == VRF_UNKNOWN)
 | |
| 						    ? -1
 | |
| 						    : (int64_t)bgp->vrf_id);
 | |
| 			json_object_string_add(
 | |
| 				json, "vrfName",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 					? VRF_DEFAULT_NAME
 | |
| 					: bgp->name);
 | |
| 
 | |
| 			if (!is_first)
 | |
| 				vty_out(vty, ",\n");
 | |
| 			else
 | |
| 				is_first = 0;
 | |
| 
 | |
| 			vty_out(vty, "\"%s\":",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 					? VRF_DEFAULT_NAME
 | |
| 					: bgp->name);
 | |
| 		} else {
 | |
| 			vty_out(vty, "\nInstance %s:\n",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 					? VRF_DEFAULT_NAME
 | |
| 					: bgp->name);
 | |
| 		}
 | |
| 
 | |
| 		if (type == show_peer || type == show_ipv4_peer ||
 | |
| 		    type == show_ipv6_peer) {
 | |
| 			ret = str2sockunion(ip_str, &su);
 | |
| 			if (ret < 0)
 | |
| 				bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
 | |
| 						  use_json, json);
 | |
| 			else
 | |
| 				bgp_show_neighbor(vty, bgp, type, &su, NULL,
 | |
| 						  use_json, json);
 | |
| 		} else {
 | |
| 			bgp_show_neighbor(vty, bgp, type, NULL, NULL,
 | |
| 					  use_json, json);
 | |
| 		}
 | |
| 		json_object_free(json);
 | |
| 		json = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (use_json)
 | |
| 		vty_out(vty, "}\n");
 | |
| 	else if (!nbr_output)
 | |
| 		vty_out(vty, "%% BGP instance not found\n");
 | |
| }
 | |
| 
 | |
| static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
 | |
| 				 enum show_type type, const char *ip_str,
 | |
| 				 bool use_json)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct bgp *bgp;
 | |
| 	union sockunion su;
 | |
| 	json_object *json = NULL;
 | |
| 
 | |
| 	if (name) {
 | |
| 		if (strmatch(name, "all")) {
 | |
| 			bgp_show_all_instances_neighbors_vty(vty, type, ip_str,
 | |
| 							     use_json);
 | |
| 			return CMD_SUCCESS;
 | |
| 		} else {
 | |
| 			bgp = bgp_lookup_by_name(name);
 | |
| 			if (!bgp) {
 | |
| 				if (use_json) {
 | |
| 					json = json_object_new_object();
 | |
| 					vty_json(vty, json);
 | |
| 				} else
 | |
| 					vty_out(vty,
 | |
| 						"%% BGP instance not found\n");
 | |
| 
 | |
| 				return CMD_WARNING;
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		bgp = bgp_get_default();
 | |
| 	}
 | |
| 
 | |
| 	if (bgp) {
 | |
| 		json = json_object_new_object();
 | |
| 		if (ip_str) {
 | |
| 			ret = str2sockunion(ip_str, &su);
 | |
| 			if (ret < 0)
 | |
| 				bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
 | |
| 						  use_json, json);
 | |
| 			else
 | |
| 				bgp_show_neighbor(vty, bgp, type, &su, NULL,
 | |
| 						  use_json, json);
 | |
| 		} else {
 | |
| 			bgp_show_neighbor(vty, bgp, type, NULL, NULL, use_json,
 | |
| 					  json);
 | |
| 		}
 | |
| 		json_object_free(json);
 | |
| 	} else {
 | |
| 		if (use_json)
 | |
| 			vty_out(vty, "{}\n");
 | |
| 		else
 | |
| 			vty_out(vty, "%% BGP instance not found\n");
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /* "show [ip] bgp neighbors graceful-restart" commands.  */
 | |
| DEFUN (show_ip_bgp_neighbors_graceful_restart,
 | |
| 	show_ip_bgp_neighbors_graceful_restart_cmd,
 | |
| 	"show bgp [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] graceful-restart [json]",
 | |
| 	SHOW_STR
 | |
| 	BGP_STR
 | |
| 	IP_STR
 | |
| 	IPV6_STR
 | |
| 	NEIGHBOR_STR
 | |
| 	"Neighbor to display information about\n"
 | |
| 	"Neighbor to display information about\n"
 | |
| 	"Neighbor on BGP configured interface\n"
 | |
| 	GR_SHOW
 | |
|        JSON_STR)
 | |
| {
 | |
| 	char *sh_arg = NULL;
 | |
| 	enum show_type sh_type;
 | |
| 	int idx = 0;
 | |
| 	afi_t afi = AFI_MAX;
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 
 | |
| 	if (!argv_find_and_parse_afi(argv, argc, &idx, &afi))
 | |
| 		afi = AFI_MAX;
 | |
| 
 | |
| 	idx++;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "A.B.C.D", &idx)
 | |
| 	    || argv_find(argv, argc, "X:X::X:X", &idx)
 | |
| 	    || argv_find(argv, argc, "WORD", &idx)) {
 | |
| 		sh_type = show_peer;
 | |
| 		sh_arg = argv[idx]->arg;
 | |
| 	} else
 | |
| 		sh_type = show_all;
 | |
| 
 | |
| 	if (!argv_find(argv, argc, "graceful-restart", &idx))
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 
 | |
| 	return bgp_show_neighbor_graceful_restart_afi_all(vty, sh_type, sh_arg,
 | |
| 							  afi, uj);
 | |
| }
 | |
| 
 | |
| /* "show [ip] bgp neighbors" commands.  */
 | |
| DEFUN (show_ip_bgp_neighbors,
 | |
|        show_ip_bgp_neighbors_cmd,
 | |
|        "show [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] [json]",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        BGP_AF_STR
 | |
|        BGP_AF_STR
 | |
|        "Detailed information on TCP and BGP neighbor connections\n"
 | |
|        "Neighbor to display information about\n"
 | |
|        "Neighbor to display information about\n"
 | |
|        "Neighbor on BGP configured interface\n"
 | |
|        JSON_STR)
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	char *sh_arg = NULL;
 | |
| 	enum show_type sh_type;
 | |
| 	afi_t afi = AFI_MAX;
 | |
| 
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	/* [<vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx))
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 
 | |
| 	idx++;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "ipv4", &idx)) {
 | |
| 		sh_type = show_ipv4_all;
 | |
| 		afi = AFI_IP;
 | |
| 	} else if (argv_find(argv, argc, "ipv6", &idx)) {
 | |
| 		sh_type = show_ipv6_all;
 | |
| 		afi = AFI_IP6;
 | |
| 	} else {
 | |
| 		sh_type = show_all;
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find(argv, argc, "A.B.C.D", &idx)
 | |
| 	    || argv_find(argv, argc, "X:X::X:X", &idx)
 | |
| 	    || argv_find(argv, argc, "WORD", &idx)) {
 | |
| 		sh_type = show_peer;
 | |
| 		sh_arg = argv[idx]->arg;
 | |
| 	}
 | |
| 
 | |
| 	if (sh_type == show_peer && afi == AFI_IP) {
 | |
| 		sh_type = show_ipv4_peer;
 | |
| 	} else if (sh_type == show_peer && afi == AFI_IP6) {
 | |
| 		sh_type = show_ipv6_peer;
 | |
| 	}
 | |
| 
 | |
| 	return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
 | |
| }
 | |
| 
 | |
| /* Show BGP's AS paths internal data.  There are both `show [ip] bgp
 | |
|    paths' and `show ip mbgp paths'.  Those functions results are the
 | |
|    same.*/
 | |
| DEFUN (show_ip_bgp_paths,
 | |
|        show_ip_bgp_paths_cmd,
 | |
|        "show [ip] bgp ["BGP_SAFI_CMD_STR"] paths",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_SAFI_HELP_STR
 | |
|        "Path information\n")
 | |
| {
 | |
| 	vty_out(vty, "Address Refcnt Path\n");
 | |
| 	aspath_print_all_vty(vty);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| #include "hash.h"
 | |
| 
 | |
| static void community_show_all_iterator(struct hash_bucket *bucket,
 | |
| 					struct vty *vty)
 | |
| {
 | |
| 	struct community *com;
 | |
| 
 | |
| 	com = (struct community *)bucket->data;
 | |
| 	vty_out(vty, "[%p] (%ld) %s\n", (void *)com, com->refcnt,
 | |
| 		community_str(com, false, false));
 | |
| }
 | |
| 
 | |
| /* Show BGP's community internal data. */
 | |
| DEFUN (show_ip_bgp_community_info,
 | |
|        show_ip_bgp_community_info_cmd,
 | |
|        "show [ip] bgp community-info",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "List all bgp community information\n")
 | |
| {
 | |
| 	vty_out(vty, "Address Refcnt Community\n");
 | |
| 
 | |
| 	hash_iterate(community_hash(),
 | |
| 		     (void (*)(struct hash_bucket *,
 | |
| 			       void *))community_show_all_iterator,
 | |
| 		     vty);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void lcommunity_show_all_iterator(struct hash_bucket *bucket,
 | |
| 					 struct vty *vty)
 | |
| {
 | |
| 	struct lcommunity *lcom;
 | |
| 
 | |
| 	lcom = (struct lcommunity *)bucket->data;
 | |
| 	vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt,
 | |
| 		lcommunity_str(lcom, false, false));
 | |
| }
 | |
| 
 | |
| /* Show BGP's community internal data. */
 | |
| DEFUN (show_ip_bgp_lcommunity_info,
 | |
|        show_ip_bgp_lcommunity_info_cmd,
 | |
|        "show ip bgp large-community-info",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "List all bgp large-community information\n")
 | |
| {
 | |
| 	vty_out(vty, "Address Refcnt Large-community\n");
 | |
| 
 | |
| 	hash_iterate(lcommunity_hash(),
 | |
| 		     (void (*)(struct hash_bucket *,
 | |
| 			       void *))lcommunity_show_all_iterator,
 | |
| 		     vty);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| /* Graceful Restart */
 | |
| 
 | |
| static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
 | |
| 						      struct bgp *bgp)
 | |
| {
 | |
| 
 | |
| 
 | |
| 	vty_out(vty, "\n%s", SHOW_GR_HEADER);
 | |
| 
 | |
| 	enum global_mode bgp_global_gr_mode = bgp_global_gr_mode_get(bgp);
 | |
| 
 | |
| 	switch (bgp_global_gr_mode) {
 | |
| 
 | |
| 	case GLOBAL_HELPER:
 | |
| 		vty_out(vty, "Global BGP GR Mode :  Helper\n");
 | |
| 		break;
 | |
| 
 | |
| 	case GLOBAL_GR:
 | |
| 		vty_out(vty, "Global BGP GR Mode :  Restart\n");
 | |
| 		break;
 | |
| 
 | |
| 	case GLOBAL_DISABLE:
 | |
| 		vty_out(vty, "Global BGP GR Mode :  Disable\n");
 | |
| 		break;
 | |
| 
 | |
| 	case GLOBAL_INVALID:
 | |
| 		vty_out(vty,
 | |
| 			"Global BGP GR Mode  Invalid\n");
 | |
| 		break;
 | |
| 	}
 | |
| 	vty_out(vty, "\n");
 | |
| }
 | |
| 
 | |
| static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
 | |
| 						      enum show_type type,
 | |
| 						      const char *ip_str,
 | |
| 						      afi_t afi, bool use_json)
 | |
| {
 | |
| 	json_object *json = NULL;
 | |
| 
 | |
| 	if (use_json)
 | |
| 		json = json_object_new_object();
 | |
| 
 | |
| 	if ((afi == AFI_MAX) && (ip_str == NULL)) {
 | |
| 		afi = AFI_IP;
 | |
| 
 | |
| 		while ((afi != AFI_L2VPN) && (afi < AFI_MAX)) {
 | |
| 
 | |
| 			bgp_show_neighbor_graceful_restart_vty(
 | |
| 				vty, type, ip_str, afi, json);
 | |
| 			afi++;
 | |
| 		}
 | |
| 	} else if (afi != AFI_MAX) {
 | |
| 		bgp_show_neighbor_graceful_restart_vty(vty, type, ip_str, afi,
 | |
| 						       json);
 | |
| 	} else {
 | |
| 		if (json)
 | |
| 			json_object_free(json);
 | |
| 		return CMD_ERR_INCOMPLETE;
 | |
| 	}
 | |
| 
 | |
| 	if (json)
 | |
| 		vty_json(vty, json);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| /* Graceful Restart */
 | |
| 
 | |
| DEFUN (show_ip_bgp_attr_info,
 | |
|        show_ip_bgp_attr_info_cmd,
 | |
|        "show [ip] bgp attribute-info",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "List all bgp attribute information\n")
 | |
| {
 | |
| 	attr_show_all(vty);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
 | |
| 				   afi_t afi, safi_t safi,
 | |
| 				   bool use_json, json_object *json)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct listnode *node;
 | |
| 	char *vname;
 | |
| 	char *ecom_str;
 | |
| 	enum vpn_policy_direction dir;
 | |
| 
 | |
| 	if (json) {
 | |
| 		json_object *json_import_vrfs = NULL;
 | |
| 		json_object *json_export_vrfs = NULL;
 | |
| 
 | |
| 		bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 | |
| 
 | |
| 		if (!bgp) {
 | |
| 			vty_json(vty, json);
 | |
| 
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 
 | |
| 		/* Provide context for the block */
 | |
| 		json_object_string_add(json, "vrf", name ? name : "default");
 | |
| 		json_object_string_add(json, "afiSafi",
 | |
| 				       get_afi_safi_str(afi, safi, true));
 | |
| 
 | |
| 		if (!CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 				BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
 | |
| 			json_object_string_add(json, "importFromVrfs", "none");
 | |
| 			json_object_string_add(json, "importRts", "none");
 | |
| 		} else {
 | |
| 			json_import_vrfs = json_object_new_array();
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(
 | |
| 						bgp->vpn_policy[afi].import_vrf,
 | |
| 						node, vname))
 | |
| 				json_object_array_add(json_import_vrfs,
 | |
| 						json_object_new_string(vname));
 | |
| 
 | |
| 			json_object_object_add(json, "importFromVrfs",
 | |
| 						       json_import_vrfs);
 | |
| 			dir = BGP_VPN_POLICY_DIR_FROMVPN;
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir]) {
 | |
| 				ecom_str = ecommunity_ecom2str(
 | |
| 					bgp->vpn_policy[afi].rtlist[dir],
 | |
| 					ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 | |
| 				json_object_string_add(json, "importRts",
 | |
| 						       ecom_str);
 | |
| 				XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
 | |
| 			} else
 | |
| 				json_object_string_add(json, "importRts",
 | |
| 						       "none");
 | |
| 		}
 | |
| 
 | |
| 		if (!CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 				BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
 | |
| 			json_object_string_add(json, "exportToVrfs", "none");
 | |
| 			json_object_string_add(json, "routeDistinguisher",
 | |
| 					       "none");
 | |
| 			json_object_string_add(json, "exportRts", "none");
 | |
| 		} else {
 | |
| 			json_export_vrfs = json_object_new_array();
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(
 | |
| 						bgp->vpn_policy[afi].export_vrf,
 | |
| 						node, vname))
 | |
| 				json_object_array_add(json_export_vrfs,
 | |
| 						json_object_new_string(vname));
 | |
| 			json_object_object_add(json, "exportToVrfs",
 | |
| 					       json_export_vrfs);
 | |
| 			json_object_string_addf(
 | |
| 				json, "routeDistinguisher", "%s",
 | |
| 				bgp->vpn_policy[afi].tovpn_rd_pretty);
 | |
| 			dir = BGP_VPN_POLICY_DIR_TOVPN;
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir]) {
 | |
| 				ecom_str = ecommunity_ecom2str(
 | |
| 					       bgp->vpn_policy[afi].rtlist[dir],
 | |
| 					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 | |
| 				json_object_string_add(json, "exportRts",
 | |
| 						       ecom_str);
 | |
| 				XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
 | |
| 			} else
 | |
| 				json_object_string_add(json, "exportRts",
 | |
| 						       "none");
 | |
| 		}
 | |
| 
 | |
| 		if (use_json) {
 | |
| 			vty_json(vty, json);
 | |
| 		}
 | |
| 	} else {
 | |
| 		bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 | |
| 
 | |
| 		if (!bgp) {
 | |
| 			vty_out(vty, "%% No such BGP instance exist\n");
 | |
| 			return CMD_WARNING;
 | |
| 		}
 | |
| 
 | |
| 		if (!CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 				BGP_CONFIG_VRF_TO_VRF_IMPORT))
 | |
| 			vty_out(vty,
 | |
| 		     "This VRF is not importing %s routes from any other VRF\n",
 | |
| 		      get_afi_safi_str(afi, safi, false));
 | |
| 		else {
 | |
| 			vty_out(vty,
 | |
| 		   "This VRF is importing %s routes from the following VRFs:\n",
 | |
| 		    get_afi_safi_str(afi, safi, false));
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(
 | |
| 						bgp->vpn_policy[afi].import_vrf,
 | |
| 						node, vname))
 | |
| 				vty_out(vty, "  %s\n", vname);
 | |
| 
 | |
| 			dir = BGP_VPN_POLICY_DIR_FROMVPN;
 | |
| 			ecom_str = NULL;
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir]) {
 | |
| 				ecom_str = ecommunity_ecom2str(
 | |
| 					       bgp->vpn_policy[afi].rtlist[dir],
 | |
| 					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 | |
| 				vty_out(vty, "Import RT(s): %s\n", ecom_str);
 | |
| 
 | |
| 				XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
 | |
| 			} else
 | |
| 				vty_out(vty, "Import RT(s):\n");
 | |
| 		}
 | |
| 
 | |
| 		if (!CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 				BGP_CONFIG_VRF_TO_VRF_EXPORT))
 | |
| 			vty_out(vty,
 | |
| 		       "This VRF is not exporting %s routes to any other VRF\n",
 | |
| 			get_afi_safi_str(afi, safi, false));
 | |
| 		else {
 | |
| 			vty_out(vty,
 | |
| 		       "This VRF is exporting %s routes to the following VRFs:\n",
 | |
| 			get_afi_safi_str(afi, safi, false));
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(
 | |
| 						bgp->vpn_policy[afi].export_vrf,
 | |
| 						node, vname))
 | |
| 				vty_out(vty, "  %s\n", vname);
 | |
| 
 | |
| 			vty_out(vty, "RD: ");
 | |
| 			vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
 | |
| 				&bgp->vpn_policy[afi].tovpn_rd);
 | |
| 			vty_out(vty, "\n");
 | |
| 
 | |
| 			dir = BGP_VPN_POLICY_DIR_TOVPN;
 | |
| 			if (bgp->vpn_policy[afi].rtlist[dir]) {
 | |
| 				ecom_str = ecommunity_ecom2str(
 | |
| 					bgp->vpn_policy[afi].rtlist[dir],
 | |
| 					ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 | |
| 				vty_out(vty, "Export RT: %s\n", ecom_str);
 | |
| 				XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
 | |
| 			} else
 | |
| 				vty_out(vty, "Import RT(s):\n");
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
 | |
| 						safi_t safi, bool use_json)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 	char *vrf_name = NULL;
 | |
| 	json_object *json = NULL;
 | |
| 	json_object *json_vrf = NULL;
 | |
| 	json_object *json_vrfs = NULL;
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json = json_object_new_object();
 | |
| 		json_vrfs = json_object_new_object();
 | |
| 	}
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 
 | |
| 		if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 			vrf_name = bgp->name;
 | |
| 
 | |
| 		if (use_json) {
 | |
| 			json_vrf = json_object_new_object();
 | |
| 		} else {
 | |
| 			vty_out(vty, "\nInstance %s:\n",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 				? VRF_DEFAULT_NAME : bgp->name);
 | |
| 		}
 | |
| 		bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf);
 | |
| 		if (use_json) {
 | |
| 			if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 				json_object_object_add(json_vrfs,
 | |
| 						VRF_DEFAULT_NAME, json_vrf);
 | |
| 			else
 | |
| 				json_object_object_add(json_vrfs, vrf_name,
 | |
| 						       json_vrf);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (use_json) {
 | |
| 		json_object_object_add(json, "vrfs", json_vrfs);
 | |
| 		vty_json(vty, json);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "show [ip] bgp route-leak" command.  */
 | |
| DEFUN (show_ip_bgp_route_leak,
 | |
| 	show_ip_bgp_route_leak_cmd,
 | |
| 	"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] route-leak  [json]",
 | |
| 	SHOW_STR
 | |
| 	IP_STR
 | |
| 	BGP_STR
 | |
| 	BGP_INSTANCE_HELP_STR
 | |
| 	BGP_AFI_HELP_STR
 | |
| 	BGP_SAFI_HELP_STR
 | |
| 	"Route leaking information\n"
 | |
| 	JSON_STR)
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	afi_t afi = AFI_MAX;
 | |
| 	safi_t safi = SAFI_MAX;
 | |
| 
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 	int idx = 0;
 | |
| 	json_object *json = NULL;
 | |
| 
 | |
| 	/* show [ip] bgp */
 | |
| 	if (argv_find(argv, argc, "ip", &idx)) {
 | |
| 		afi = AFI_IP;
 | |
| 		safi = SAFI_UNICAST;
 | |
| 	}
 | |
| 	/* [vrf VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "view", &idx)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% This command is not applicable to BGP views\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	}
 | |
| 	/* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */
 | |
| 	if (argv_find_and_parse_afi(argv, argc, &idx, &afi))
 | |
| 		argv_find_and_parse_safi(argv, argc, &idx, &safi);
 | |
| 
 | |
| 	if (!((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)) {
 | |
| 		vty_out(vty,
 | |
| 			"%% This command is applicable only for unicast ipv4|ipv6\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	if (vrf && strmatch(vrf, "all"))
 | |
| 		return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj);
 | |
| 
 | |
| 	if (uj)
 | |
| 		json = json_object_new_object();
 | |
| 
 | |
| 	return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json);
 | |
| }
 | |
| 
 | |
| static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
 | |
| 					       safi_t safi, bool uj)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
 | |
| 		if (!uj)
 | |
| 			vty_out(vty, "\nInstance %s:\n",
 | |
| 				(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
 | |
| 					? VRF_DEFAULT_NAME
 | |
| 					: bgp->name);
 | |
| 
 | |
| 		update_group_show(bgp, afi, safi, vty, 0, uj);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int bgp_show_update_groups(struct vty *vty, const char *name, int afi,
 | |
| 				  int safi, uint64_t subgrp_id, bool uj)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	if (name) {
 | |
| 		if (strmatch(name, "all")) {
 | |
| 			bgp_show_all_instances_updgrps_vty(vty, afi, safi, uj);
 | |
| 			return CMD_SUCCESS;
 | |
| 		} else {
 | |
| 			bgp = bgp_lookup_by_name(name);
 | |
| 		}
 | |
| 	} else {
 | |
| 		bgp = bgp_get_default();
 | |
| 	}
 | |
| 
 | |
| 	if (bgp)
 | |
| 		update_group_show(bgp, afi, safi, vty, subgrp_id, uj);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_ip_bgp_updgrps,
 | |
|        show_ip_bgp_updgrps_cmd,
 | |
|        "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID] [json]",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        BGP_AFI_HELP_STR
 | |
|        BGP_SAFI_WITH_LABEL_HELP_STR
 | |
|        "Detailed info about dynamic update groups\n"
 | |
|        "Specific subgroup to display detailed info for\n"
 | |
|        JSON_STR)
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	afi_t afi = AFI_IP6;
 | |
| 	safi_t safi = SAFI_UNICAST;
 | |
| 	uint64_t subgrp_id = 0;
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 
 | |
| 	/* show [ip] bgp */
 | |
| 	if (argv_find(argv, argc, "ip", &idx))
 | |
| 		afi = AFI_IP;
 | |
| 	/* [<vrf> VIEWVRFNAME] */
 | |
| 	if (argv_find(argv, argc, "vrf", &idx)) {
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 		if (vrf && strmatch(vrf, VRF_DEFAULT_NAME))
 | |
| 			vrf = NULL;
 | |
| 	} else if (argv_find(argv, argc, "view", &idx))
 | |
| 		/* [<view> VIEWVRFNAME] */
 | |
| 		vrf = argv[idx + 1]->arg;
 | |
| 	/* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */
 | |
| 	if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
 | |
| 		argv_find_and_parse_safi(argv, argc, &idx, &safi);
 | |
| 	}
 | |
| 
 | |
| 	/* get subgroup id, if provided */
 | |
| 	idx = argc - 1;
 | |
| 	if (argv[idx]->type == VARIABLE_TKN)
 | |
| 		subgrp_id = strtoull(argv[idx]->arg, NULL, 10);
 | |
| 
 | |
| 	return (bgp_show_update_groups(vty, vrf, afi, safi, subgrp_id, uj));
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_instance_all_ipv6_updgrps,
 | |
|        show_bgp_instance_all_ipv6_updgrps_cmd,
 | |
|        "show [ip] bgp <view|vrf> all update-groups [json]",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_ALL_HELP_STR
 | |
|        "Detailed info about dynamic update groups\n"
 | |
|        JSON_STR)
 | |
| {
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 
 | |
| 	bgp_show_all_instances_updgrps_vty(vty, AFI_IP6, SAFI_UNICAST, uj);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_l2vpn_evpn_updgrps,
 | |
| 	show_bgp_l2vpn_evpn_updgrps_cmd,
 | |
| 	"show [ip] bgp l2vpn evpn update-groups",
 | |
| 	SHOW_STR
 | |
| 	IP_STR
 | |
| 	BGP_STR
 | |
| 	"l2vpn address family\n"
 | |
| 	"evpn sub-address family\n"
 | |
| 	"Detailed info about dynamic update groups\n")
 | |
| {
 | |
| 	char *vrf = NULL;
 | |
| 	uint64_t subgrp_id = 0;
 | |
| 
 | |
| 	bgp_show_update_groups(vty, vrf, AFI_L2VPN, SAFI_EVPN, subgrp_id, 0);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_updgrps_stats,
 | |
|        show_bgp_updgrps_stats_cmd,
 | |
|        "show [ip] bgp update-groups statistics",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        "Detailed info about dynamic update groups\n"
 | |
|        "Statistics\n")
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	bgp = bgp_get_default();
 | |
| 	if (bgp)
 | |
| 		update_group_show_stats(bgp, vty);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_bgp_instance_updgrps_stats,
 | |
|        show_bgp_instance_updgrps_stats_cmd,
 | |
|        "show [ip] bgp <view|vrf> VIEWVRFNAME update-groups statistics",
 | |
|        SHOW_STR
 | |
|        IP_STR
 | |
|        BGP_STR
 | |
|        BGP_INSTANCE_HELP_STR
 | |
|        "Detailed info about dynamic update groups\n"
 | |
|        "Statistics\n")
 | |
| {
 | |
| 	int idx_word = 3;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	bgp = bgp_lookup_by_name(argv[idx_word]->arg);
 | |
| 	if (bgp)
 | |
| 		update_group_show_stats(bgp, vty);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void show_bgp_updgrps_adj_info_aux(struct vty *vty, const char *name,
 | |
| 					  afi_t afi, safi_t safi,
 | |
| 					  const char *what, uint64_t subgrp_id)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	if (name)
 | |
| 		bgp = bgp_lookup_by_name(name);
 | |
| 	else
 | |
| 		bgp = bgp_get_default();
 | |
| 
 | |
| 	if (bgp) {
 | |
| 		if (!strcmp(what, "advertise-queue"))
 | |
| 			update_group_show_adj_queue(bgp, afi, safi, vty,
 | |
| 						    subgrp_id);
 | |
| 		else if (!strcmp(what, "advertised-routes"))
 | |
| 			update_group_show_advertised(bgp, afi, safi, vty,
 | |
| 						     subgrp_id);
 | |
| 		else if (!strcmp(what, "packet-queue"))
 | |
| 			update_group_show_packet_queue(bgp, afi, safi, vty,
 | |
| 						       subgrp_id);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFPY(show_ip_bgp_instance_updgrps_adj_s,
 | |
|       show_ip_bgp_instance_updgrps_adj_s_cmd,
 | |
|       "show [ip]$ip bgp [<view|vrf> VIEWVRFNAME$vrf] [<ipv4|ipv6>$afi <unicast|multicast|vpn>$safi] update-groups [SUBGROUP-ID]$sgid <advertise-queue|advertised-routes|packet-queue>$rtq",
 | |
|       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
 | |
| 	      BGP_SAFI_HELP_STR
 | |
|       "Detailed info about dynamic update groups\n"
 | |
|       "Specific subgroup to display info for\n"
 | |
|       "Advertisement queue\n"
 | |
|       "Announced routes\n"
 | |
|       "Packet queue\n")
 | |
| {
 | |
| 	uint64_t subgrp_id = 0;
 | |
| 	afi_t afiz;
 | |
| 	safi_t safiz;
 | |
| 	if (sgid)
 | |
| 		subgrp_id = strtoull(sgid, NULL, 10);
 | |
| 
 | |
| 	if (!ip && !afi)
 | |
| 		afiz = AFI_IP6;
 | |
| 	if (!ip && afi)
 | |
| 		afiz = bgp_vty_afi_from_str(afi);
 | |
| 	if (ip && !afi)
 | |
| 		afiz = AFI_IP;
 | |
| 	if (ip && afi) {
 | |
| 		afiz = bgp_vty_afi_from_str(afi);
 | |
| 		if (afiz != AFI_IP)
 | |
| 			vty_out(vty,
 | |
| 				"%% Cannot specify both 'ip' and 'ipv6'\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST;
 | |
| 
 | |
| 	show_bgp_updgrps_adj_info_aux(vty, vrf, afiz, safiz, rtq, subgrp_id);
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
 | |
| 				   json_object *json)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct prefix *range;
 | |
| 	struct peer *conf;
 | |
| 	struct peer *peer;
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	const char *peer_status;
 | |
| 	int lr_count;
 | |
| 	int dynamic;
 | |
| 	bool af_cfgd;
 | |
| 	json_object *json_peer_group = NULL;
 | |
| 	json_object *json_peer_group_afc = NULL;
 | |
| 	json_object *json_peer_group_members = NULL;
 | |
| 	json_object *json_peer_group_dynamic = NULL;
 | |
| 	json_object *json_peer_group_dynamic_af = NULL;
 | |
| 	json_object *json_peer_group_ranges = NULL;
 | |
| 
 | |
| 	conf = group->conf;
 | |
| 
 | |
| 	if (json) {
 | |
| 		json_peer_group = json_object_new_object();
 | |
| 		json_peer_group_afc = json_object_new_array();
 | |
| 	}
 | |
| 
 | |
| 	if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
 | |
| 		if (json)
 | |
| 			asn_asn2json(json_peer_group, "remoteAs", conf->as,
 | |
| 				     bgp_get_asnotation(conf->bgp));
 | |
| 		else {
 | |
| 			vty_out(vty, "\nBGP peer-group %s, remote AS ",
 | |
| 				group->name);
 | |
| 			vty_out(vty, ASN_FORMAT(bgp_get_asnotation(conf->bgp)),
 | |
| 				&conf->as);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 	} else if (conf->as_type == AS_INTERNAL) {
 | |
| 		if (json)
 | |
| 			asn_asn2json(json, "remoteAs", group->bgp->as,
 | |
| 				     group->bgp->asnotation);
 | |
| 		else
 | |
| 			vty_out(vty, "\nBGP peer-group %s, remote AS %s\n",
 | |
| 				group->name, group->bgp->as_pretty);
 | |
| 	} else {
 | |
| 		if (!json)
 | |
| 			vty_out(vty, "\nBGP peer-group %s\n", group->name);
 | |
| 	}
 | |
| 
 | |
| 	if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) {
 | |
| 		if (json)
 | |
| 			json_object_string_add(json_peer_group, "type",
 | |
| 					       "internal");
 | |
| 		else
 | |
| 			vty_out(vty, "  Peer-group type is internal\n");
 | |
| 	} else {
 | |
| 		if (json)
 | |
| 			json_object_string_add(json_peer_group, "type",
 | |
| 					       "external");
 | |
| 		else
 | |
| 			vty_out(vty, "  Peer-group type is external\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Display AFs configured. */
 | |
| 	if (!json)
 | |
| 		vty_out(vty, "  Configured address-families:");
 | |
| 
 | |
| 	FOREACH_AFI_SAFI (afi, safi) {
 | |
| 		if (conf->afc[afi][safi]) {
 | |
| 			af_cfgd = true;
 | |
| 			if (json)
 | |
| 				json_object_array_add(
 | |
| 					json_peer_group_afc,
 | |
| 					json_object_new_string(get_afi_safi_str(
 | |
| 						afi, safi, false)));
 | |
| 			else
 | |
| 				vty_out(vty, " %s;",
 | |
| 					get_afi_safi_str(afi, safi, false));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (json) {
 | |
| 		json_object_object_add(json_peer_group,
 | |
| 				       "addressFamiliesConfigured",
 | |
| 				       json_peer_group_afc);
 | |
| 	} else {
 | |
| 		if (!af_cfgd)
 | |
| 			vty_out(vty, " none\n");
 | |
| 		else
 | |
| 			vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Display listen ranges (for dynamic neighbors), if any */
 | |
| 	for (afi = AFI_IP; afi < AFI_MAX; afi++) {
 | |
| 		lr_count = listcount(group->listen_range[afi]);
 | |
| 		if (lr_count) {
 | |
| 			if (json) {
 | |
| 				if (!json_peer_group_dynamic)
 | |
| 					json_peer_group_dynamic =
 | |
| 						json_object_new_object();
 | |
| 
 | |
| 				json_peer_group_dynamic_af =
 | |
| 					json_object_new_object();
 | |
| 				json_peer_group_ranges =
 | |
| 					json_object_new_array();
 | |
| 				json_object_int_add(json_peer_group_dynamic_af,
 | |
| 						    "count", lr_count);
 | |
| 			} else {
 | |
| 				vty_out(vty, "  %d %s listen range(s)\n",
 | |
| 					lr_count, afi2str(afi));
 | |
| 			}
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS(group->listen_range[afi], node,
 | |
| 					       nnode, range)) {
 | |
| 				if (json) {
 | |
| 					char buf[BUFSIZ];
 | |
| 
 | |
| 					snprintfrr(buf, sizeof(buf), "%pFX",
 | |
| 						   range);
 | |
| 
 | |
| 					json_object_array_add(
 | |
| 						json_peer_group_ranges,
 | |
| 						json_object_new_string(buf));
 | |
| 				} else {
 | |
| 					vty_out(vty, "    %pFX\n", range);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (json) {
 | |
| 				json_object_object_add(
 | |
| 					json_peer_group_dynamic_af, "ranges",
 | |
| 					json_peer_group_ranges);
 | |
| 
 | |
| 				json_object_object_add(
 | |
| 					json_peer_group_dynamic, afi2str(afi),
 | |
| 					json_peer_group_dynamic_af);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (json_peer_group_dynamic)
 | |
| 		json_object_object_add(json_peer_group, "dynamicRanges",
 | |
| 				       json_peer_group_dynamic);
 | |
| 
 | |
| 	/* Display group members and their status */
 | |
| 	if (listcount(group->peer)) {
 | |
| 		if (json)
 | |
| 			json_peer_group_members = json_object_new_object();
 | |
| 		else
 | |
| 			vty_out(vty, "  Peer-group members:\n");
 | |
| 		for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
 | |
| 			    || CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
 | |
| 				peer_status = "Idle (Admin)";
 | |
| 			else if (CHECK_FLAG(peer->sflags,
 | |
| 					    PEER_STATUS_PREFIX_OVERFLOW))
 | |
| 				peer_status = "Idle (PfxCt)";
 | |
| 			else
 | |
| 				peer_status = lookup_msg(bgp_status_msg,
 | |
| 							 peer->status, NULL);
 | |
| 
 | |
| 			dynamic = peer_dynamic_neighbor(peer);
 | |
| 
 | |
| 			if (json) {
 | |
| 				json_object *json_peer_group_member =
 | |
| 					json_object_new_object();
 | |
| 
 | |
| 				json_object_string_add(json_peer_group_member,
 | |
| 						       "status", peer_status);
 | |
| 
 | |
| 				if (dynamic)
 | |
| 					json_object_boolean_true_add(
 | |
| 						json_peer_group_member,
 | |
| 						"dynamic");
 | |
| 
 | |
| 				json_object_object_add(json_peer_group_members,
 | |
| 						       peer->host,
 | |
| 						       json_peer_group_member);
 | |
| 			} else {
 | |
| 				vty_out(vty, "    %s %s %s \n", peer->host,
 | |
| 					dynamic ? "(dynamic)" : "",
 | |
| 					peer_status);
 | |
| 			}
 | |
| 		}
 | |
| 		if (json)
 | |
| 			json_object_object_add(json_peer_group, "members",
 | |
| 					       json_peer_group_members);
 | |
| 	}
 | |
| 
 | |
| 	if (json)
 | |
| 		json_object_object_add(json, group->name, json_peer_group);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int bgp_show_peer_group_vty(struct vty *vty, const char *name,
 | |
| 				   const char *group_name, bool uj)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct peer_group *group;
 | |
| 	bool found = false;
 | |
| 	json_object *json = NULL;
 | |
| 
 | |
| 	if (uj)
 | |
| 		json = json_object_new_object();
 | |
| 
 | |
| 	bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 | |
| 
 | |
| 	if (!bgp) {
 | |
| 		if (uj)
 | |
| 			vty_json(vty, json);
 | |
| 		else
 | |
| 			vty_out(vty, "%% BGP instance not found\n");
 | |
| 
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
 | |
| 		if (group_name) {
 | |
| 			if (strmatch(group->name, group_name)) {
 | |
| 				bgp_show_one_peer_group(vty, group, json);
 | |
| 				found = true;
 | |
| 				break;
 | |
| 			}
 | |
| 		} else {
 | |
| 			bgp_show_one_peer_group(vty, group, json);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (group_name && !found && !uj)
 | |
| 		vty_out(vty, "%% No such peer-group\n");
 | |
| 
 | |
| 	if (uj)
 | |
| 		vty_json(vty, json);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd,
 | |
|       "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME] [json]",
 | |
|       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR
 | |
|       "Detailed information on BGP peer groups\n"
 | |
|       "Peer group name\n" JSON_STR)
 | |
| {
 | |
| 	char *vrf, *pg;
 | |
| 	int idx = 0;
 | |
| 	bool uj = use_json(argc, argv);
 | |
| 
 | |
| 	vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
 | |
| 							 : NULL;
 | |
| 	pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
 | |
| 
 | |
| 	return bgp_show_peer_group_vty(vty, vrf, pg, uj);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Redistribute VTY commands.  */
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4,
 | |
|        bgp_redistribute_ipv4_cmd,
 | |
|        "redistribute " FRR_IP_REDIST_STR_BGPD,
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int type;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_redist_add(bgp, AFI_IP, type, 0);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, type, 0, false);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4, bgp_redistribute_ipv4_hidden_cmd,
 | |
| 	"redistribute " FRR_IP_REDIST_STR_BGPD,
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD)
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_rmap,
 | |
|        bgp_redistribute_ipv4_rmap_cmd,
 | |
|        "redistribute " FRR_IP_REDIST_STR_BGPD " route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int type;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map = route_map_lookup_warn_noexist(
 | |
| 		vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, type, 0);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_rmap, bgp_redistribute_ipv4_rmap_hidden_cmd,
 | |
| 	"redistribute " FRR_IP_REDIST_STR_BGPD " route-map RMAP_NAME",
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_metric,
 | |
|        bgp_redistribute_ipv4_metric_cmd,
 | |
|        "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, type, 0);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_metric, bgp_redistribute_ipv4_metric_hidden_cmd,
 | |
| 	"redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295)",
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_rmap_metric,
 | |
|        bgp_redistribute_ipv4_rmap_metric_cmd,
 | |
|        "redistribute " FRR_IP_REDIST_STR_BGPD " route-map RMAP_NAME metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int idx_number = 5;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, type, 0);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_rmap_metric,
 | |
| 	bgp_redistribute_ipv4_rmap_metric_hidden_cmd,
 | |
| 	"redistribute " FRR_IP_REDIST_STR_BGPD
 | |
| 	" route-map RMAP_NAME metric (0-4294967295)",
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n"
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_metric_rmap,
 | |
|        bgp_redistribute_ipv4_metric_rmap_cmd,
 | |
|        "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295) route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_word = 5;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, type, 0);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, type, metric);
 | |
| 	changed |=
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, type, 0, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_metric_rmap,
 | |
| 	bgp_redistribute_ipv4_metric_rmap_hidden_cmd,
 | |
| 	"redistribute " FRR_IP_REDIST_STR_BGPD
 | |
| 	" metric (0-4294967295) route-map RMAP_NAME",
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n"
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_ospf,
 | |
|        bgp_redistribute_ipv4_ospf_cmd,
 | |
|        "redistribute <ospf|table> (1-65535)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 1;
 | |
| 	int idx_number = 2;
 | |
| 	unsigned short instance;
 | |
| 	unsigned short protocol;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	bgp_redist_add(bgp, AFI_IP, protocol, instance);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, false);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_hidden_cmd,
 | |
| 	     "redistribute <ospf|table> (1-65535)",
 | |
| 	     "Redistribute information from another routing protocol\n"
 | |
| 	     "Open Shortest Path First (OSPFv2)\n"
 | |
| 	     "Non-main Kernel Routing Table\n"
 | |
| 	     "Instance ID/Table ID\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_ospf_rmap,
 | |
|        bgp_redistribute_ipv4_ospf_rmap_cmd,
 | |
|        "redistribute <ospf|table> (1-65535) route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 1;
 | |
| 	int idx_number = 2;
 | |
| 	int idx_word = 4;
 | |
| 	struct bgp_redist *red;
 | |
| 	unsigned short instance;
 | |
| 	int protocol;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_rmap,
 | |
| 	     bgp_redistribute_ipv4_ospf_rmap_hidden_cmd,
 | |
| 	     "redistribute <ospf|table> (1-65535) route-map RMAP_NAME",
 | |
| 	     "Redistribute information from another routing protocol\n"
 | |
| 	     "Open Shortest Path First (OSPFv2)\n"
 | |
| 	     "Non-main Kernel Routing Table\n"
 | |
| 	     "Instance ID/Table ID\n"
 | |
| 	     "Route map reference\n"
 | |
| 	     "Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_ospf_metric,
 | |
|        bgp_redistribute_ipv4_ospf_metric_cmd,
 | |
|        "redistribute <ospf|table> (1-65535) metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 1;
 | |
| 	int idx_number = 2;
 | |
| 	int idx_number_2 = 4;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	unsigned short instance;
 | |
| 	int protocol;
 | |
| 	bool changed;
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
 | |
| 						metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_metric,
 | |
| 	     bgp_redistribute_ipv4_ospf_metric_hidden_cmd,
 | |
| 	     "redistribute <ospf|table> (1-65535) metric (0-4294967295)",
 | |
| 	     "Redistribute information from another routing protocol\n"
 | |
| 	     "Open Shortest Path First (OSPFv2)\n"
 | |
| 	     "Non-main Kernel Routing Table\n"
 | |
| 	     "Instance ID/Table ID\n"
 | |
| 	     "Metric for redistributed routes\n"
 | |
| 	     "Default metric\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric,
 | |
|        bgp_redistribute_ipv4_ospf_rmap_metric_cmd,
 | |
|        "redistribute <ospf|table> (1-65535) route-map RMAP_NAME metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 1;
 | |
| 	int idx_number = 2;
 | |
| 	int idx_word = 4;
 | |
| 	int idx_number_2 = 6;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	unsigned short instance;
 | |
| 	int protocol;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
 | |
| 						metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_ospf_rmap_metric,
 | |
| 	bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd,
 | |
| 	"redistribute <ospf|table> (1-65535) route-map RMAP_NAME metric (0-4294967295)",
 | |
| 	"Redistribute information from another routing protocol\n"
 | |
| 	"Open Shortest Path First (OSPFv2)\n"
 | |
| 	"Non-main Kernel Routing Table\n"
 | |
| 	"Instance ID/Table ID\n"
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n"
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap,
 | |
|        bgp_redistribute_ipv4_ospf_metric_rmap_cmd,
 | |
|        "redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 1;
 | |
| 	int idx_number = 2;
 | |
| 	int idx_number_2 = 4;
 | |
| 	int idx_word = 6;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	unsigned short instance;
 | |
| 	int protocol;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	metric = strtoul(argv[idx_number_2]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP, protocol, instance);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP, protocol,
 | |
| 						metric);
 | |
| 	changed |=
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, changed);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	bgp_redistribute_ipv4_ospf_metric_rmap,
 | |
| 	bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd,
 | |
| 	"redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map RMAP_NAME",
 | |
| 	"Redistribute information from another routing protocol\n"
 | |
| 	"Open Shortest Path First (OSPFv2)\n"
 | |
| 	"Non-main Kernel Routing Table\n"
 | |
| 	"Instance ID/Table ID\n"
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n"
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (no_bgp_redistribute_ipv4_ospf,
 | |
|        no_bgp_redistribute_ipv4_ospf_cmd,
 | |
|        "no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]",
 | |
|        NO_STR
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        "Open Shortest Path First (OSPFv2)\n"
 | |
|        "Non-main Kernel Routing Table\n"
 | |
|        "Instance ID/Table ID\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_ospf_table = 2;
 | |
| 	int idx_number = 3;
 | |
| 	unsigned short instance;
 | |
| 	int protocol;
 | |
| 
 | |
| 	if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
 | |
| 		protocol = ZEBRA_ROUTE_OSPF;
 | |
| 	else
 | |
| 		protocol = ZEBRA_ROUTE_TABLE;
 | |
| 
 | |
| 	instance = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 	return bgp_redistribute_unset(bgp, AFI_IP, protocol, instance);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_hidden_cmd,
 | |
| 	"no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]",
 | |
| 	NO_STR
 | |
| 	"Redistribute information from another routing protocol\n"
 | |
| 	"Open Shortest Path First (OSPFv2)\n"
 | |
| 	"Non-main Kernel Routing Table\n"
 | |
| 	"Instance ID/Table ID\n"
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n"
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (no_bgp_redistribute_ipv4,
 | |
|        no_bgp_redistribute_ipv4_cmd,
 | |
|        "no redistribute " FRR_IP_REDIST_STR_BGPD " [{metric (0-4294967295)|route-map RMAP_NAME}]",
 | |
|        NO_STR
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 2;
 | |
| 	int type;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return bgp_redistribute_unset(bgp, AFI_IP, type, 0);
 | |
| }
 | |
| 
 | |
| ALIAS_HIDDEN(
 | |
| 	no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_hidden_cmd,
 | |
| 	"no redistribute " FRR_IP_REDIST_STR_BGPD
 | |
| 	" [{metric (0-4294967295)|route-map RMAP_NAME}]",
 | |
| 	NO_STR
 | |
| 	"Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD
 | |
| 	"Metric for redistributed routes\n"
 | |
| 	"Default metric\n"
 | |
| 	"Route map reference\n"
 | |
| 	"Pointer to route-map entries\n")
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv6,
 | |
|        bgp_redistribute_ipv6_cmd,
 | |
|        "redistribute " FRR_IP6_REDIST_STR_BGPD,
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD)
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int type;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	bgp_redist_add(bgp, AFI_IP6, type, 0);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP6, type, 0, false);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv6_rmap,
 | |
|        bgp_redistribute_ipv6_rmap_cmd,
 | |
|        "redistribute " FRR_IP6_REDIST_STR_BGPD " route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int type;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP6, type, 0);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv6_metric,
 | |
|        bgp_redistribute_ipv6_metric_cmd,
 | |
|        "redistribute " FRR_IP6_REDIST_STR_BGPD " metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP6, type, 0);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP6, type, metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv6_rmap_metric,
 | |
|        bgp_redistribute_ipv6_rmap_metric_cmd,
 | |
|        "redistribute " FRR_IP6_REDIST_STR_BGPD " route-map RMAP_NAME metric (0-4294967295)",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n"
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_word = 3;
 | |
| 	int idx_number = 5;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP6, type, 0);
 | |
| 	changed =
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP6, type,
 | |
| 						metric);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
 | |
| }
 | |
| 
 | |
| DEFUN (bgp_redistribute_ipv6_metric_rmap,
 | |
|        bgp_redistribute_ipv6_metric_rmap_cmd,
 | |
|        "redistribute " FRR_IP6_REDIST_STR_BGPD " metric (0-4294967295) route-map RMAP_NAME",
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 1;
 | |
| 	int idx_number = 3;
 | |
| 	int idx_word = 5;
 | |
| 	int type;
 | |
| 	uint32_t metric;
 | |
| 	struct bgp_redist *red;
 | |
| 	bool changed;
 | |
| 	struct route_map *route_map =
 | |
| 		route_map_lookup_warn_noexist(vty, argv[idx_word]->arg);
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	metric = strtoul(argv[idx_number]->arg, NULL, 10);
 | |
| 
 | |
| 	red = bgp_redist_add(bgp, AFI_IP6, type, 0);
 | |
| 	changed = bgp_redistribute_metric_set(bgp, red, AFI_IP6, SAFI_UNICAST,
 | |
| 						metric);
 | |
| 	changed |=
 | |
| 		bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map);
 | |
| 	return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
 | |
| }
 | |
| 
 | |
| DEFUN (no_bgp_redistribute_ipv6,
 | |
|        no_bgp_redistribute_ipv6_cmd,
 | |
|        "no redistribute " FRR_IP6_REDIST_STR_BGPD " [{metric (0-4294967295)|route-map RMAP_NAME}]",
 | |
|        NO_STR
 | |
|        "Redistribute information from another routing protocol\n"
 | |
|        FRR_IP6_REDIST_HELP_STR_BGPD
 | |
|        "Metric for redistributed routes\n"
 | |
|        "Default metric\n"
 | |
|        "Route map reference\n"
 | |
|        "Pointer to route-map entries\n")
 | |
| {
 | |
| 	VTY_DECLVAR_CONTEXT(bgp, bgp);
 | |
| 	int idx_protocol = 2;
 | |
| 	int type;
 | |
| 
 | |
| 	type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text);
 | |
| 	if (type < 0) {
 | |
| 		vty_out(vty, "%% Invalid route type\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return bgp_redistribute_unset(bgp, AFI_IP6, type, 0);
 | |
| }
 | |
| 
 | |
| /* Neighbor update tcp-mss. */
 | |
| static int peer_tcp_mss_vty(struct vty *vty, const char *peer_str,
 | |
| 			    const char *tcp_mss_str)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	uint32_t tcp_mss_val = 0;
 | |
| 
 | |
| 	peer = peer_and_group_lookup_vty(vty, peer_str);
 | |
| 	if (!peer)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	if (tcp_mss_str) {
 | |
| 		tcp_mss_val = strtoul(tcp_mss_str, NULL, 10);
 | |
| 		peer_tcp_mss_set(peer, tcp_mss_val);
 | |
| 	} else {
 | |
| 		peer_tcp_mss_unset(peer);
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN(neighbor_tcp_mss, neighbor_tcp_mss_cmd,
 | |
|       "neighbor <A.B.C.D|X:X::X:X|WORD> tcp-mss (1-65535)",
 | |
|       NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "TCP max segment size\n"
 | |
|       "TCP MSS value\n")
 | |
| {
 | |
| 	int peer_index = 1;
 | |
| 	int mss_index = 3;
 | |
| 
 | |
| 	vty_out(vty,
 | |
| 		" Warning: Reset BGP session for tcp-mss value to take effect\n");
 | |
| 	return peer_tcp_mss_vty(vty, argv[peer_index]->arg,
 | |
| 				argv[mss_index]->arg);
 | |
| }
 | |
| 
 | |
| DEFUN(no_neighbor_tcp_mss, no_neighbor_tcp_mss_cmd,
 | |
|       "no neighbor <A.B.C.D|X:X::X:X|WORD> tcp-mss [(1-65535)]",
 | |
|       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
 | |
|       "TCP max segment size\n"
 | |
|       "TCP MSS value\n")
 | |
| {
 | |
| 	int peer_index = 2;
 | |
| 
 | |
| 	vty_out(vty,
 | |
| 		" Warning: Reset BGP session for tcp-mss value to take effect\n");
 | |
| 	return peer_tcp_mss_vty(vty, argv[peer_index]->arg, NULL);
 | |
| }
 | |
| 
 | |
| DEFPY(bgp_retain_route_target, bgp_retain_route_target_cmd,
 | |
|       "[no$no] bgp retain route-target all",
 | |
|       NO_STR BGP_STR
 | |
|       "Retain BGP updates\n"
 | |
|       "Retain BGP updates based on route-target values\n"
 | |
|       "Retain all BGP updates\n")
 | |
| {
 | |
| 	bool check;
 | |
| 	struct bgp *bgp = VTY_GET_CONTEXT(bgp);
 | |
| 
 | |
| 	check = CHECK_FLAG(bgp->af_flags[bgp_node_afi(vty)][bgp_node_safi(vty)],
 | |
| 			   BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
 | |
| 	if (check != !no) {
 | |
| 		if (!no)
 | |
| 			SET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
 | |
| 					      [bgp_node_safi(vty)],
 | |
| 				 BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
 | |
| 		else
 | |
| 			UNSET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
 | |
| 						[bgp_node_safi(vty)],
 | |
| 				   BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
 | |
| 		/* trigger a flush to re-sync with ADJ-RIB-in */
 | |
| 		bgp_clear(vty, bgp, bgp_node_afi(vty), bgp_node_safi(vty),
 | |
| 			  clear_all, BGP_CLEAR_SOFT_IN, NULL);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp,
 | |
| 					  afi_t afi, safi_t safi)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	/* Unicast redistribution only.  */
 | |
| 	if (safi != SAFI_UNICAST)
 | |
| 		return;
 | |
| 
 | |
| 	for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
 | |
| 		/* Redistribute BGP does not make sense.  */
 | |
| 		if (i != ZEBRA_ROUTE_BGP) {
 | |
| 			struct list *red_list;
 | |
| 			struct listnode *node;
 | |
| 			struct bgp_redist *red;
 | |
| 
 | |
| 			red_list = bgp->redist[afi][i];
 | |
| 			if (!red_list)
 | |
| 				continue;
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
 | |
| 				/* "redistribute" configuration.  */
 | |
| 				vty_out(vty, "  redistribute %s",
 | |
| 					zebra_route_string(i));
 | |
| 				if (red->instance)
 | |
| 					vty_out(vty, " %d", red->instance);
 | |
| 				if (red->redist_metric_flag)
 | |
| 					vty_out(vty, " metric %u",
 | |
| 						red->redist_metric);
 | |
| 				if (red->rmap.name)
 | |
| 					vty_out(vty, " route-map %s",
 | |
| 						red->rmap.name);
 | |
| 				vty_out(vty, "\n");
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* peer-group helpers for config-write */
 | |
| 
 | |
| bool peergroup_flag_check(struct peer *peer, uint64_t flag)
 | |
| {
 | |
| 	if (!peer_group_active(peer)) {
 | |
| 		if (CHECK_FLAG(peer->flags_invert, flag))
 | |
| 			return !CHECK_FLAG(peer->flags, flag);
 | |
| 		else
 | |
| 			return !!CHECK_FLAG(peer->flags, flag);
 | |
| 	}
 | |
| 
 | |
| 	return !!CHECK_FLAG(peer->flags_override, flag);
 | |
| }
 | |
| 
 | |
| static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
 | |
| 				    uint64_t flag)
 | |
| {
 | |
| 	if (!peer_group_active(peer)) {
 | |
| 		if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag))
 | |
| 			return !peer_af_flag_check(peer, afi, safi, flag);
 | |
| 		else
 | |
| 			return peer_af_flag_check(peer, afi, safi, flag);
 | |
| 	}
 | |
| 
 | |
| 	return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag);
 | |
| }
 | |
| 
 | |
| static bool peergroup_filter_check(struct peer *peer, afi_t afi, safi_t safi,
 | |
| 				   uint8_t type, int direct)
 | |
| {
 | |
| 	struct bgp_filter *filter;
 | |
| 
 | |
| 	if (peer_group_active(peer))
 | |
| 		return !!CHECK_FLAG(peer->filter_override[afi][safi][direct],
 | |
| 				    type);
 | |
| 
 | |
| 	filter = &peer->filter[afi][safi];
 | |
| 	switch (type) {
 | |
| 	case PEER_FT_DISTRIBUTE_LIST:
 | |
| 		return !!(filter->dlist[direct].name);
 | |
| 	case PEER_FT_FILTER_LIST:
 | |
| 		return !!(filter->aslist[direct].name);
 | |
| 	case PEER_FT_PREFIX_LIST:
 | |
| 		return !!(filter->plist[direct].name);
 | |
| 	case PEER_FT_ROUTE_MAP:
 | |
| 		return !!(filter->map[direct].name);
 | |
| 	case PEER_FT_UNSUPPRESS_MAP:
 | |
| 		return !!(filter->usmap.name);
 | |
| 	case PEER_FT_ADVERTISE_MAP:
 | |
| 		return !!(filter->advmap.aname
 | |
| 			  && ((filter->advmap.condition == direct)
 | |
| 			      && filter->advmap.cname));
 | |
| 	default:
 | |
| 		return false;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Return true if the addpath type is set for peer and different from
 | |
|  * peer-group.
 | |
|  */
 | |
| static bool peergroup_af_addpath_check(struct peer *peer, afi_t afi,
 | |
| 				       safi_t safi)
 | |
| {
 | |
| 	enum bgp_addpath_strat type, g_type;
 | |
| 
 | |
| 	type = peer->addpath_type[afi][safi];
 | |
| 
 | |
| 	if (type != BGP_ADDPATH_NONE) {
 | |
| 		if (peer_group_active(peer)) {
 | |
| 			g_type = peer->group->conf->addpath_type[afi][safi];
 | |
| 
 | |
| 			if (type != g_type)
 | |
| 				return true;
 | |
| 			else
 | |
| 				return false;
 | |
| 		}
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| /* This is part of the address-family block (unicast only) */
 | |
| static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
 | |
| 					    afi_t afi)
 | |
| {
 | |
| 	int indent = 2;
 | |
| 	uint32_t tovpn_sid_index = 0;
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) {
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 			       BGP_CONFIG_VRF_TO_VRF_IMPORT))
 | |
| 			vty_out(vty, "%*simport vrf route-map %s\n", indent, "",
 | |
| 				bgp->vpn_policy[afi]
 | |
| 				.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]);
 | |
| 		else
 | |
| 			vty_out(vty, "%*sroute-map vpn import %s\n", indent, "",
 | |
| 				bgp->vpn_policy[afi]
 | |
| 				.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]);
 | |
| 	}
 | |
| 	if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 		       BGP_CONFIG_VRF_TO_VRF_IMPORT)
 | |
| 	    || CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
 | |
| 			  BGP_CONFIG_VRF_TO_VRF_EXPORT))
 | |
| 		return;
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 		BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
 | |
| 
 | |
| 		vty_out(vty, "%*slabel vpn export %s\n", indent, "", "auto");
 | |
| 
 | |
| 	} else {
 | |
| 		if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
 | |
| 			vty_out(vty, "%*slabel vpn export %u\n", indent, "",
 | |
| 				bgp->vpn_policy[afi].tovpn_label);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 		       BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP))
 | |
| 		vty_out(vty,
 | |
| 			"%*slabel vpn export allocation-mode per-nexthop\n",
 | |
| 			indent, "");
 | |
| 
 | |
| 	tovpn_sid_index = bgp->vpn_policy[afi].tovpn_sid_index;
 | |
| 	if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 		       BGP_VPN_POLICY_TOVPN_SID_AUTO)) {
 | |
| 		vty_out(vty, "%*ssid vpn export %s\n", indent, "", "auto");
 | |
| 	} else if (tovpn_sid_index != 0) {
 | |
| 		vty_out(vty, "%*ssid vpn export %d\n", indent, "",
 | |
| 			tovpn_sid_index);
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET))
 | |
| 		vty_out(vty, "%*srd vpn export %s\n", indent, "",
 | |
| 			bgp->vpn_policy[afi].tovpn_rd_pretty);
 | |
| 
 | |
| 	if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
 | |
| 		       BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
 | |
| 
 | |
| 		char buf[PREFIX_STRLEN];
 | |
| 		if (inet_ntop(bgp->vpn_policy[afi].tovpn_nexthop.family,
 | |
| 			      &bgp->vpn_policy[afi].tovpn_nexthop.u.prefix, buf,
 | |
| 			      sizeof(buf))) {
 | |
| 
 | |
| 			vty_out(vty, "%*snexthop vpn export %s\n",
 | |
| 				indent, "", buf);
 | |
| 		}
 | |
| 	}
 | |
| 	if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]
 | |
| 	    && bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]
 | |
| 	    && ecommunity_cmp(
 | |
| 		       bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
 | |
| 		       bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN])) {
 | |
| 
 | |
| 		char *b = ecommunity_ecom2str(
 | |
| 			bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN],
 | |
| 			ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
 | |
| 		vty_out(vty, "%*srt vpn both %s\n", indent, "", b);
 | |
| 		XFREE(MTYPE_ECOMMUNITY_STR, b);
 | |
| 	} else {
 | |
| 		if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
 | |
| 			char *b = ecommunity_ecom2str(
 | |
| 				bgp->vpn_policy[afi]
 | |
| 					.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
 | |
| 				ECOMMUNITY_FORMAT_ROUTE_MAP,
 | |
| 				ECOMMUNITY_ROUTE_TARGET);
 | |
| 			vty_out(vty, "%*srt vpn import %s\n", indent, "", b);
 | |
| 			XFREE(MTYPE_ECOMMUNITY_STR, b);
 | |
| 		}
 | |
| 		if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
 | |
| 			char *b = ecommunity_ecom2str(
 | |
| 				bgp->vpn_policy[afi]
 | |
| 					.rtlist[BGP_VPN_POLICY_DIR_TOVPN],
 | |
| 				ECOMMUNITY_FORMAT_ROUTE_MAP,
 | |
| 				ECOMMUNITY_ROUTE_TARGET);
 | |
| 			vty_out(vty, "%*srt vpn export %s\n", indent, "", b);
 | |
| 			XFREE(MTYPE_ECOMMUNITY_STR, b);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN])
 | |
| 		vty_out(vty, "%*sroute-map vpn export %s\n", indent, "",
 | |
| 			bgp->vpn_policy[afi]
 | |
| 				.rmap_name[BGP_VPN_POLICY_DIR_TOVPN]);
 | |
| 
 | |
| 	if (bgp->vpn_policy[afi].import_redirect_rtlist) {
 | |
| 		char *b = ecommunity_ecom2str(
 | |
| 					bgp->vpn_policy[afi]
 | |
| 					.import_redirect_rtlist,
 | |
| 					ECOMMUNITY_FORMAT_ROUTE_MAP,
 | |
| 					ECOMMUNITY_ROUTE_TARGET);
 | |
| 
 | |
| 		if (bgp->vpn_policy[afi].import_redirect_rtlist->unit_size
 | |
| 		    != ECOMMUNITY_SIZE)
 | |
| 			vty_out(vty, "%*srt6 redirect import %s\n",
 | |
| 				indent, "", b);
 | |
| 		else
 | |
| 			vty_out(vty, "%*srt redirect import %s\n",
 | |
| 				indent, "", b);
 | |
| 		XFREE(MTYPE_ECOMMUNITY_STR, b);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_config_write_filter(struct vty *vty, struct peer *peer,
 | |
| 				    afi_t afi, safi_t safi)
 | |
| {
 | |
| 	struct bgp_filter *filter;
 | |
| 	char *addr;
 | |
| 
 | |
| 	addr = peer->host;
 | |
| 	filter = &peer->filter[afi][safi];
 | |
| 
 | |
| 	/* distribute-list. */
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST,
 | |
| 				   FILTER_IN))
 | |
| 		vty_out(vty, "  neighbor %s distribute-list %s in\n", addr,
 | |
| 			filter->dlist[FILTER_IN].name);
 | |
| 
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST,
 | |
| 				   FILTER_OUT))
 | |
| 		vty_out(vty, "  neighbor %s distribute-list %s out\n", addr,
 | |
| 			filter->dlist[FILTER_OUT].name);
 | |
| 
 | |
| 	/* prefix-list. */
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST,
 | |
| 				   FILTER_IN))
 | |
| 		vty_out(vty, "  neighbor %s prefix-list %s in\n", addr,
 | |
| 			filter->plist[FILTER_IN].name);
 | |
| 
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST,
 | |
| 				   FILTER_OUT))
 | |
| 		vty_out(vty, "  neighbor %s prefix-list %s out\n", addr,
 | |
| 			filter->plist[FILTER_OUT].name);
 | |
| 
 | |
| 	/* route-map. */
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, RMAP_IN))
 | |
| 		vty_out(vty, "  neighbor %s route-map %s in\n", addr,
 | |
| 			filter->map[RMAP_IN].name);
 | |
| 
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP,
 | |
| 				   RMAP_OUT))
 | |
| 		vty_out(vty, "  neighbor %s route-map %s out\n", addr,
 | |
| 			filter->map[RMAP_OUT].name);
 | |
| 
 | |
| 	/* unsuppress-map */
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_UNSUPPRESS_MAP, 0))
 | |
| 		vty_out(vty, "  neighbor %s unsuppress-map %s\n", addr,
 | |
| 			filter->usmap.name);
 | |
| 
 | |
| 	/* advertise-map : always applied in OUT direction*/
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_ADVERTISE_MAP,
 | |
| 				   CONDITION_NON_EXIST))
 | |
| 		vty_out(vty,
 | |
| 			"  neighbor %s advertise-map %s non-exist-map %s\n",
 | |
| 			addr, filter->advmap.aname, filter->advmap.cname);
 | |
| 
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_ADVERTISE_MAP,
 | |
| 				   CONDITION_EXIST))
 | |
| 		vty_out(vty, "  neighbor %s advertise-map %s exist-map %s\n",
 | |
| 			addr, filter->advmap.aname, filter->advmap.cname);
 | |
| 
 | |
| 	/* filter-list. */
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST,
 | |
| 				   FILTER_IN))
 | |
| 		vty_out(vty, "  neighbor %s filter-list %s in\n", addr,
 | |
| 			filter->aslist[FILTER_IN].name);
 | |
| 
 | |
| 	if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST,
 | |
| 				   FILTER_OUT))
 | |
| 		vty_out(vty, "  neighbor %s filter-list %s out\n", addr,
 | |
| 			filter->aslist[FILTER_OUT].name);
 | |
| }
 | |
| 
 | |
| /* BGP peer configuration display function. */
 | |
| static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
 | |
| 					 struct peer *peer)
 | |
| {
 | |
| 	struct peer *g_peer = NULL;
 | |
| 	char *addr;
 | |
| 	int if_pg_printed = false;
 | |
| 	int if_ras_printed = false;
 | |
| 
 | |
| 	/* Skip dynamic neighbors. */
 | |
| 	if (peer_dynamic_neighbor(peer))
 | |
| 		return;
 | |
| 
 | |
| 	if (peer->conf_if)
 | |
| 		addr = peer->conf_if;
 | |
| 	else
 | |
| 		addr = peer->host;
 | |
| 
 | |
| 	/************************************
 | |
| 	 ****** Global to the neighbor ******
 | |
| 	 ************************************/
 | |
| 	if (peer->conf_if) {
 | |
| 		if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
 | |
| 			vty_out(vty, " neighbor %s interface v6only", addr);
 | |
| 		else
 | |
| 			vty_out(vty, " neighbor %s interface", addr);
 | |
| 
 | |
| 		if (peer_group_active(peer)) {
 | |
| 			vty_out(vty, " peer-group %s", peer->group->name);
 | |
| 			if_pg_printed = true;
 | |
| 		} else if (peer->as_type == AS_SPECIFIED) {
 | |
| 			vty_out(vty, " remote-as %s", peer->as_pretty);
 | |
| 			if_ras_printed = true;
 | |
| 		} else if (peer->as_type == AS_INTERNAL) {
 | |
| 			vty_out(vty, " remote-as internal");
 | |
| 			if_ras_printed = true;
 | |
| 		} else if (peer->as_type == AS_EXTERNAL) {
 | |
| 			vty_out(vty, " remote-as external");
 | |
| 			if_ras_printed = true;
 | |
| 		}
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* remote-as and peer-group */
 | |
| 	/* peer is a member of a peer-group */
 | |
| 	if (peer_group_active(peer)) {
 | |
| 		g_peer = peer->group->conf;
 | |
| 
 | |
| 		if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) {
 | |
| 			if (peer->as_type == AS_SPECIFIED) {
 | |
| 				vty_out(vty, " neighbor %s remote-as %s\n",
 | |
| 					addr, peer->as_pretty);
 | |
| 			} else if (peer->as_type == AS_INTERNAL) {
 | |
| 				vty_out(vty,
 | |
| 					" neighbor %s remote-as internal\n",
 | |
| 					addr);
 | |
| 			} else if (peer->as_type == AS_EXTERNAL) {
 | |
| 				vty_out(vty,
 | |
| 					" neighbor %s remote-as external\n",
 | |
| 					addr);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/* For swpX peers we displayed the peer-group
 | |
| 		 * via 'neighbor swpX interface peer-group PGNAME' */
 | |
| 		if (!if_pg_printed)
 | |
| 			vty_out(vty, " neighbor %s peer-group %s\n", addr,
 | |
| 				peer->group->name);
 | |
| 	}
 | |
| 
 | |
| 	/* peer is NOT a member of a peer-group */
 | |
| 	else {
 | |
| 		/* peer is a peer-group, declare the peer-group */
 | |
| 		if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
 | |
| 			vty_out(vty, " neighbor %s peer-group\n", addr);
 | |
| 		}
 | |
| 
 | |
| 		if (!if_ras_printed) {
 | |
| 			if (peer->as_type == AS_SPECIFIED) {
 | |
| 				vty_out(vty, " neighbor %s remote-as %s\n",
 | |
| 					addr, peer->as_pretty);
 | |
| 			} else if (peer->as_type == AS_INTERNAL) {
 | |
| 				vty_out(vty,
 | |
| 					" neighbor %s remote-as internal\n",
 | |
| 					addr);
 | |
| 			} else if (peer->as_type == AS_EXTERNAL) {
 | |
| 				vty_out(vty,
 | |
| 					" neighbor %s remote-as external\n",
 | |
| 					addr);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* local-as */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) {
 | |
| 		vty_out(vty, " neighbor %s local-as %s", addr,
 | |
| 			peer->change_local_as_pretty);
 | |
| 		if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND))
 | |
| 			vty_out(vty, " no-prepend");
 | |
| 		if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
 | |
| 			vty_out(vty, " replace-as");
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* description */
 | |
| 	if (peer->desc) {
 | |
| 		vty_out(vty, " neighbor %s description %s\n", addr, peer->desc);
 | |
| 	}
 | |
| 
 | |
| 	/* shutdown */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_SHUTDOWN)) {
 | |
| 		if (peer->tx_shutdown_message)
 | |
| 			vty_out(vty, " neighbor %s shutdown message %s\n", addr,
 | |
| 				peer->tx_shutdown_message);
 | |
| 		else
 | |
| 			vty_out(vty, " neighbor %s shutdown\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_RTT_SHUTDOWN))
 | |
| 		vty_out(vty, " neighbor %s shutdown rtt %u count %u\n", addr,
 | |
| 			peer->rtt_expected, peer->rtt_keepalive_conf);
 | |
| 
 | |
| 	/* bfd */
 | |
| 	if (peer->bfd_config)
 | |
| 		bgp_bfd_peer_config_write(vty, peer, addr);
 | |
| 
 | |
| 	/* password */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))
 | |
| 		vty_out(vty, " neighbor %s password %s\n", addr,
 | |
| 			peer->password);
 | |
| 
 | |
| 	/* neighbor solo */
 | |
| 	if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) {
 | |
| 		if (!peer_group_active(peer)) {
 | |
| 			vty_out(vty, " neighbor %s solo\n", addr);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* BGP port */
 | |
| 	if (peer->port != BGP_PORT_DEFAULT) {
 | |
| 		vty_out(vty, " neighbor %s port %d\n", addr, peer->port);
 | |
| 	}
 | |
| 
 | |
| 	/* Local interface name */
 | |
| 	if (peer->ifname) {
 | |
| 		vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname);
 | |
| 	}
 | |
| 
 | |
| 	/* TCP max segment size */
 | |
| 	if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS))
 | |
| 		vty_out(vty, " neighbor %s tcp-mss %d\n", addr, peer->tcp_mss);
 | |
| 
 | |
| 	/* passive */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE))
 | |
| 		vty_out(vty, " neighbor %s passive\n", addr);
 | |
| 
 | |
| 	/* ebgp-multihop */
 | |
| 	if (peer->sort != BGP_PEER_IBGP && peer->ttl != BGP_DEFAULT_TTL
 | |
| 	    && !(peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED
 | |
| 		 && peer->ttl == MAXTTL)) {
 | |
| 		if (!peer_group_active(peer) || g_peer->ttl != peer->ttl) {
 | |
| 			vty_out(vty, " neighbor %s ebgp-multihop %d\n", addr,
 | |
| 				peer->ttl);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* aigp */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
 | |
| 		vty_out(vty, " neighbor %s aigp\n", addr);
 | |
| 
 | |
| 	/* graceful-shutdown */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 		vty_out(vty, " neighbor %s graceful-shutdown\n", addr);
 | |
| 
 | |
| 	/* role */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
 | |
| 	    peer->local_role != ROLE_UNDEFINED)
 | |
| 		vty_out(vty, " neighbor %s local-role %s%s\n", addr,
 | |
| 			bgp_get_name_by_role(peer->local_role),
 | |
| 			CHECK_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE)
 | |
| 				? " strict-mode"
 | |
| 				: "");
 | |
| 
 | |
| 	/* ttl-security hops */
 | |
| 	if (peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) {
 | |
| 		if (!peer_group_active(peer)
 | |
| 		    || g_peer->gtsm_hops != peer->gtsm_hops) {
 | |
| 			vty_out(vty, " neighbor %s ttl-security hops %d\n",
 | |
| 				addr, peer->gtsm_hops);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* disable-connected-check */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK))
 | |
| 		vty_out(vty, " neighbor %s disable-connected-check\n", addr);
 | |
| 
 | |
| 	/* link-bw-encoding-ieee */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE))
 | |
| 		vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n",
 | |
| 			addr);
 | |
| 
 | |
| 	/* extended-optional-parameters */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS))
 | |
| 		vty_out(vty, " neighbor %s extended-optional-parameters\n",
 | |
| 			addr);
 | |
| 
 | |
| 	/* enforce-first-as */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS))
 | |
| 		vty_out(vty, " neighbor %s enforce-first-as\n", addr);
 | |
| 
 | |
| 	/* update-source */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) {
 | |
| 		if (peer->update_source)
 | |
| 			vty_out(vty, " neighbor %s update-source %pSU\n", addr,
 | |
| 				peer->update_source);
 | |
| 		else if (peer->update_if)
 | |
| 			vty_out(vty, " neighbor %s update-source %s\n", addr,
 | |
| 				peer->update_if);
 | |
| 	}
 | |
| 
 | |
| 	/* advertisement-interval */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_ROUTEADV))
 | |
| 		vty_out(vty, " neighbor %s advertisement-interval %u\n", addr,
 | |
| 			peer->routeadv);
 | |
| 
 | |
| 	/* timers */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_TIMER))
 | |
| 		vty_out(vty, " neighbor %s timers %u %u\n", addr,
 | |
| 			peer->keepalive, peer->holdtime);
 | |
| 
 | |
| 	/* timers connect */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_TIMER_CONNECT))
 | |
| 		vty_out(vty, " neighbor %s timers connect %u\n", addr,
 | |
| 			peer->connect);
 | |
| 	/* need special-case handling for changed default values due to
 | |
| 	 * config profile / version (because there is no "timers bgp connect"
 | |
| 	 * command, we need to save this per-peer :/)
 | |
| 	 */
 | |
| 	else if (!peer_group_active(peer) && !peer->connect &&
 | |
| 		 peer->bgp->default_connect_retry != SAVE_BGP_CONNECT_RETRY)
 | |
| 		vty_out(vty, " neighbor %s timers connect %u\n", addr,
 | |
| 			peer->bgp->default_connect_retry);
 | |
| 
 | |
| 	/* timers delayopen */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_TIMER_DELAYOPEN))
 | |
| 		vty_out(vty, " neighbor %s timers delayopen %u\n", addr,
 | |
| 			peer->delayopen);
 | |
| 	/* Save config even though flag is not set if default values have been
 | |
| 	 * changed
 | |
| 	 */
 | |
| 	else if (!peer_group_active(peer) && !peer->delayopen
 | |
| 		 && peer->bgp->default_delayopen != BGP_DEFAULT_DELAYOPEN)
 | |
| 		vty_out(vty, " neighbor %s timers delayopen %u\n", addr,
 | |
| 			peer->bgp->default_delayopen);
 | |
| 
 | |
| 	/* capability dynamic */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
 | |
| 		vty_out(vty, " neighbor %s capability dynamic\n", addr);
 | |
| 
 | |
| 	/* capability extended-nexthop */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
 | |
| 		if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE) &&
 | |
| 		    !peer->conf_if)
 | |
| 			vty_out(vty,
 | |
| 				" no neighbor %s capability extended-nexthop\n",
 | |
| 				addr);
 | |
| 		else if (!peer->conf_if)
 | |
| 			vty_out(vty,
 | |
| 				" neighbor %s capability extended-nexthop\n",
 | |
| 				addr);
 | |
| 	}
 | |
| 
 | |
| 	/* capability software-version */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION))
 | |
| 		vty_out(vty, " neighbor %s capability software-version\n",
 | |
| 			addr);
 | |
| 
 | |
| 	/* dont-capability-negotiation */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY))
 | |
| 		vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr);
 | |
| 
 | |
| 	/* override-capability */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY))
 | |
| 		vty_out(vty, " neighbor %s override-capability\n", addr);
 | |
| 
 | |
| 	/* strict-capability-match */
 | |
| 	if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH))
 | |
| 		vty_out(vty, " neighbor %s strict-capability-match\n", addr);
 | |
| 
 | |
| 	/* Sender side AS path loop detection. */
 | |
| 	if (peer->as_path_loop_detection)
 | |
| 		vty_out(vty, " neighbor %s sender-as-path-loop-detection\n",
 | |
| 			addr);
 | |
| 
 | |
| 	/* path-attribute discard */
 | |
| 	char discard_attrs_str[BUFSIZ] = {0};
 | |
| 	bool discard_attrs = bgp_path_attribute_discard(
 | |
| 		peer, discard_attrs_str, sizeof(discard_attrs_str));
 | |
| 
 | |
| 	if (discard_attrs)
 | |
| 		vty_out(vty, " neighbor %s path-attribute discard %s\n", addr,
 | |
| 			discard_attrs_str);
 | |
| 
 | |
| 	/* path-attribute treat-as-withdraw */
 | |
| 	char withdraw_attrs_str[BUFSIZ] = {0};
 | |
| 	bool withdraw_attrs = bgp_path_attribute_treat_as_withdraw(
 | |
| 		peer, withdraw_attrs_str, sizeof(withdraw_attrs_str));
 | |
| 
 | |
| 	if (withdraw_attrs)
 | |
| 		vty_out(vty,
 | |
| 			" neighbor %s path-attribute treat-as-withdraw %s\n",
 | |
| 			addr, withdraw_attrs_str);
 | |
| 
 | |
| 	if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
 | |
| 			PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
 | |
| 
 | |
| 		if (CHECK_FLAG(peer->peer_gr_new_status_flag,
 | |
| 			       PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) {
 | |
| 			vty_out(vty,
 | |
| 				" neighbor %s graceful-restart-helper\n", addr);
 | |
| 		} else if (CHECK_FLAG(
 | |
| 				   peer->peer_gr_new_status_flag,
 | |
| 				   PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) {
 | |
| 			vty_out(vty,
 | |
| 				" neighbor %s graceful-restart\n", addr);
 | |
| 		} else if (
 | |
| 			(!(CHECK_FLAG(peer->peer_gr_new_status_flag,
 | |
| 				      PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
 | |
| 			 && !(CHECK_FLAG(
 | |
| 				 peer->peer_gr_new_status_flag,
 | |
| 				 PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) {
 | |
| 			vty_out(vty, " neighbor %s graceful-restart-disable\n",
 | |
| 				addr);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* BGP peer configuration display function. */
 | |
| static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
 | |
| 				     struct peer *peer, afi_t afi, safi_t safi)
 | |
| {
 | |
| 	struct peer *g_peer = NULL;
 | |
| 	char *addr;
 | |
| 	bool flag_scomm, flag_secomm, flag_slcomm;
 | |
| 
 | |
| 	/* Skip dynamic neighbors. */
 | |
| 	if (peer_dynamic_neighbor(peer))
 | |
| 		return;
 | |
| 
 | |
| 	if (peer->conf_if)
 | |
| 		addr = peer->conf_if;
 | |
| 	else
 | |
| 		addr = peer->host;
 | |
| 
 | |
| 	/************************************
 | |
| 	 ****** Per AF to the neighbor ******
 | |
| 	 ************************************/
 | |
| 	if (peer_group_active(peer)) {
 | |
| 		g_peer = peer->group->conf;
 | |
| 
 | |
| 		/* If the peer-group is active but peer is not, print a 'no
 | |
| 		 * activate' */
 | |
| 		if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) {
 | |
| 			vty_out(vty, "  no neighbor %s activate\n", addr);
 | |
| 		}
 | |
| 
 | |
| 		/* If the peer-group is not active but peer is, print an
 | |
| 		   'activate' */
 | |
| 		else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) {
 | |
| 			vty_out(vty, "  neighbor %s activate\n", addr);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (peer->afc[afi][safi]) {
 | |
| 			if (safi == SAFI_ENCAP)
 | |
| 				vty_out(vty, "  neighbor %s activate\n", addr);
 | |
| 			else if (!bgp->default_af[afi][safi])
 | |
| 				vty_out(vty, "  neighbor %s activate\n", addr);
 | |
| 		} else {
 | |
| 			if (bgp->default_af[afi][safi])
 | |
| 				vty_out(vty, "  no neighbor %s activate\n",
 | |
| 					addr);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* addpath TX knobs */
 | |
| 	if (peergroup_af_addpath_check(peer, afi, safi)) {
 | |
| 		switch (peer->addpath_type[afi][safi]) {
 | |
| 		case BGP_ADDPATH_ALL:
 | |
| 			vty_out(vty, "  neighbor %s addpath-tx-all-paths\n",
 | |
| 				addr);
 | |
| 			break;
 | |
| 		case BGP_ADDPATH_BEST_PER_AS:
 | |
| 			vty_out(vty,
 | |
| 				"  neighbor %s addpath-tx-bestpath-per-AS\n",
 | |
| 				addr);
 | |
| 			break;
 | |
| 		case BGP_ADDPATH_BEST_SELECTED:
 | |
| 			if (peer->addpath_best_selected[afi][safi])
 | |
| 				vty_out(vty,
 | |
| 					"  neighbor %s addpath-tx-best-selected %u\n",
 | |
| 					addr,
 | |
| 					peer->addpath_best_selected[afi][safi]);
 | |
| 			break;
 | |
| 		case BGP_ADDPATH_MAX:
 | |
| 		case BGP_ADDPATH_NONE:
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX))
 | |
| 		vty_out(vty, "  neighbor %s disable-addpath-rx\n", addr);
 | |
| 
 | |
| 	/* ORF capability.  */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
 | |
| 	    || peergroup_af_flag_check(peer, afi, safi,
 | |
| 				       PEER_FLAG_ORF_PREFIX_RM)) {
 | |
| 		vty_out(vty, "  neighbor %s capability orf prefix-list", addr);
 | |
| 
 | |
| 		if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 					    PEER_FLAG_ORF_PREFIX_SM)
 | |
| 		    && peergroup_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_ORF_PREFIX_RM))
 | |
| 			vty_out(vty, " both");
 | |
| 		else if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 						 PEER_FLAG_ORF_PREFIX_SM))
 | |
| 			vty_out(vty, " send");
 | |
| 		else
 | |
| 			vty_out(vty, " receive");
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Route reflector client. */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_REFLECTOR_CLIENT)) {
 | |
| 		vty_out(vty, "  neighbor %s route-reflector-client\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* next-hop-self force */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_FORCE_NEXTHOP_SELF)) {
 | |
| 		vty_out(vty, "  neighbor %s next-hop-self force\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* next-hop-self */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) {
 | |
| 		vty_out(vty, "  neighbor %s next-hop-self\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* remove-private-AS */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) {
 | |
| 		vty_out(vty, "  neighbor %s remove-private-AS all replace-AS\n",
 | |
| 			addr);
 | |
| 	}
 | |
| 
 | |
| 	else if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 					 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) {
 | |
| 		vty_out(vty, "  neighbor %s remove-private-AS replace-AS\n",
 | |
| 			addr);
 | |
| 	}
 | |
| 
 | |
| 	else if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 					 PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) {
 | |
| 		vty_out(vty, "  neighbor %s remove-private-AS all\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	else if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 					 PEER_FLAG_REMOVE_PRIVATE_AS)) {
 | |
| 		vty_out(vty, "  neighbor %s remove-private-AS\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* as-override */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) {
 | |
| 		vty_out(vty, "  neighbor %s as-override\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* send-community print. */
 | |
| 	flag_scomm = peergroup_af_flag_check(peer, afi, safi,
 | |
| 					     PEER_FLAG_SEND_COMMUNITY);
 | |
| 	flag_secomm = peergroup_af_flag_check(peer, afi, safi,
 | |
| 					      PEER_FLAG_SEND_EXT_COMMUNITY);
 | |
| 	flag_slcomm = peergroup_af_flag_check(peer, afi, safi,
 | |
| 					      PEER_FLAG_SEND_LARGE_COMMUNITY);
 | |
| 
 | |
| 	if (flag_scomm && flag_secomm && flag_slcomm) {
 | |
| 		vty_out(vty, "  no neighbor %s send-community all\n", addr);
 | |
| 	} else {
 | |
| 		if (flag_scomm)
 | |
| 			vty_out(vty, "  no neighbor %s send-community\n", addr);
 | |
| 		if (flag_secomm)
 | |
| 			vty_out(vty,
 | |
| 				"  no neighbor %s send-community extended\n",
 | |
| 				addr);
 | |
| 
 | |
| 		if (flag_slcomm)
 | |
| 			vty_out(vty, "  no neighbor %s send-community large\n",
 | |
| 				addr);
 | |
| 	}
 | |
| 
 | |
| 	/* Default information */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_DEFAULT_ORIGINATE)) {
 | |
| 		vty_out(vty, "  neighbor %s default-originate", addr);
 | |
| 
 | |
| 		if (peer->default_rmap[afi][safi].name)
 | |
| 			vty_out(vty, " route-map %s",
 | |
| 				peer->default_rmap[afi][safi].name);
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Soft reconfiguration inbound. */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) {
 | |
| 		vty_out(vty, "  neighbor %s soft-reconfiguration inbound\n",
 | |
| 			addr);
 | |
| 	}
 | |
| 
 | |
| 	/* maximum-prefix. */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) {
 | |
| 		vty_out(vty, "  neighbor %s maximum-prefix %u", addr,
 | |
| 			peer->pmax[afi][safi]);
 | |
| 
 | |
| 		if (peer->pmax_threshold[afi][safi]
 | |
| 		    != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
 | |
| 			vty_out(vty, " %u", peer->pmax_threshold[afi][safi]);
 | |
| 		if (peer_af_flag_check(peer, afi, safi,
 | |
| 				       PEER_FLAG_MAX_PREFIX_WARNING))
 | |
| 			vty_out(vty, " warning-only");
 | |
| 		if (peer->pmax_restart[afi][safi])
 | |
| 			vty_out(vty, " restart %u",
 | |
| 				peer->pmax_restart[afi][safi]);
 | |
| 		if (peer_af_flag_check(peer, afi, safi,
 | |
| 				       PEER_FLAG_MAX_PREFIX_FORCE))
 | |
| 			vty_out(vty, " force");
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	/* maximum-prefix-out */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX_OUT))
 | |
| 		vty_out(vty, "  neighbor %s maximum-prefix-out %u\n",
 | |
| 			addr, peer->pmax_out[afi][safi]);
 | |
| 
 | |
| 	/* Route server client. */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_RSERVER_CLIENT)) {
 | |
| 		vty_out(vty, "  neighbor %s route-server-client\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* Nexthop-local unchanged. */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi,
 | |
| 				    PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) {
 | |
| 		vty_out(vty, "  neighbor %s nexthop-local unchanged\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* allowas-in <1-10> */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) {
 | |
| 		if (peer_af_flag_check(peer, afi, safi,
 | |
| 				       PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
 | |
| 			vty_out(vty, "  neighbor %s allowas-in origin\n", addr);
 | |
| 		} else if (peer->allowas_in[afi][safi] == 3) {
 | |
| 			vty_out(vty, "  neighbor %s allowas-in\n", addr);
 | |
| 		} else {
 | |
| 			vty_out(vty, "  neighbor %s allowas-in %d\n", addr,
 | |
| 				peer->allowas_in[afi][safi]);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* accept-own */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ACCEPT_OWN))
 | |
| 		vty_out(vty, "  neighbor %s accept-own\n", addr);
 | |
| 
 | |
| 	/* soo */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOO)) {
 | |
| 		char *soo_str = ecommunity_ecom2str(
 | |
| 			peer->soo[afi][safi], ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 | |
| 
 | |
| 		vty_out(vty, "  neighbor %s soo %s\n", addr, soo_str);
 | |
| 		XFREE(MTYPE_ECOMMUNITY_STR, soo_str);
 | |
| 	}
 | |
| 
 | |
| 	/* weight */
 | |
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT))
 | |
| 		vty_out(vty, "  neighbor %s weight %lu\n", addr,
 | |
| 			peer->weight[afi][safi]);
 | |
| 
 | |
| 	/* Filter. */
 | |
| 	bgp_config_write_filter(vty, peer, afi, safi);
 | |
| 
 | |
| 	/* atribute-unchanged. */
 | |
| 	if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED)
 | |
| 	    || (safi != SAFI_EVPN
 | |
| 		&& peer_af_flag_check(peer, afi, safi,
 | |
| 				      PEER_FLAG_NEXTHOP_UNCHANGED))
 | |
| 	    || peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) {
 | |
| 
 | |
| 		if (!peer_group_active(peer)
 | |
| 		    || peergroup_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_AS_PATH_UNCHANGED)
 | |
| 		    || peergroup_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_NEXTHOP_UNCHANGED)
 | |
| 		    || peergroup_af_flag_check(peer, afi, safi,
 | |
| 					       PEER_FLAG_MED_UNCHANGED)) {
 | |
| 
 | |
| 			vty_out(vty,
 | |
| 				"  neighbor %s attribute-unchanged%s%s%s\n",
 | |
| 				addr,
 | |
| 				peer_af_flag_check(peer, afi, safi,
 | |
| 						   PEER_FLAG_AS_PATH_UNCHANGED)
 | |
| 					? " as-path"
 | |
| 					: "",
 | |
| 				peer_af_flag_check(peer, afi, safi,
 | |
| 						   PEER_FLAG_NEXTHOP_UNCHANGED)
 | |
| 					? " next-hop"
 | |
| 					: "",
 | |
| 				peer_af_flag_check(peer, afi, safi,
 | |
| 						   PEER_FLAG_MED_UNCHANGED)
 | |
| 					? " med"
 | |
| 					: "");
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
 | |
| 				 safi_t safi)
 | |
| {
 | |
| 	if (!CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 			BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
 | |
| 		vty_out(vty, "  no bgp retain route-target all\n");
 | |
| }
 | |
| 
 | |
| /* Address family based peer configuration display.  */
 | |
| static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
 | |
| 				    safi_t safi)
 | |
| {
 | |
| 	struct peer *peer;
 | |
| 	struct peer_group *group;
 | |
| 	struct listnode *node, *nnode;
 | |
| 
 | |
| 
 | |
| 	vty_frame(vty, " !\n address-family ");
 | |
| 	if (afi == AFI_IP) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			vty_frame(vty, "ipv4 unicast");
 | |
| 		else if (safi == SAFI_LABELED_UNICAST)
 | |
| 			vty_frame(vty, "ipv4 labeled-unicast");
 | |
| 		else if (safi == SAFI_MULTICAST)
 | |
| 			vty_frame(vty, "ipv4 multicast");
 | |
| 		else if (safi == SAFI_MPLS_VPN)
 | |
| 			vty_frame(vty, "ipv4 vpn");
 | |
| 		else if (safi == SAFI_ENCAP)
 | |
| 			vty_frame(vty, "ipv4 encap");
 | |
| 		else if (safi == SAFI_FLOWSPEC)
 | |
| 			vty_frame(vty, "ipv4 flowspec");
 | |
| 	} else if (afi == AFI_IP6) {
 | |
| 		if (safi == SAFI_UNICAST)
 | |
| 			vty_frame(vty, "ipv6 unicast");
 | |
| 		else if (safi == SAFI_LABELED_UNICAST)
 | |
| 			vty_frame(vty, "ipv6 labeled-unicast");
 | |
| 		else if (safi == SAFI_MULTICAST)
 | |
| 			vty_frame(vty, "ipv6 multicast");
 | |
| 		else if (safi == SAFI_MPLS_VPN)
 | |
| 			vty_frame(vty, "ipv6 vpn");
 | |
| 		else if (safi == SAFI_ENCAP)
 | |
| 			vty_frame(vty, "ipv6 encap");
 | |
| 		else if (safi == SAFI_FLOWSPEC)
 | |
| 			vty_frame(vty, "ipv6 flowspec");
 | |
| 	} else if (afi == AFI_L2VPN) {
 | |
| 		if (safi == SAFI_EVPN)
 | |
| 			vty_frame(vty, "l2vpn evpn");
 | |
| 	}
 | |
| 	vty_frame(vty, "\n");
 | |
| 
 | |
| 	bgp_config_write_distance(vty, bgp, afi, safi);
 | |
| 
 | |
| 	bgp_config_write_network(vty, bgp, afi, safi);
 | |
| 
 | |
| 	bgp_config_write_redistribute(vty, bgp, afi, safi);
 | |
| 
 | |
| 	/* BGP flag dampening. */
 | |
| 	if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
 | |
| 		bgp_config_write_damp(vty, afi, safi);
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
 | |
| 		bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 		/* Do not display doppelganger peers */
 | |
| 		if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 			bgp_config_write_peer_af(vty, bgp, peer, afi, safi);
 | |
| 	}
 | |
| 
 | |
| 	bgp_config_write_maxpaths(vty, bgp, afi, safi);
 | |
| 	bgp_config_write_table_map(vty, bgp, afi, safi);
 | |
| 
 | |
| 	if (safi == SAFI_EVPN)
 | |
| 		bgp_config_write_evpn_info(vty, bgp, afi, safi);
 | |
| 
 | |
| 	if (safi == SAFI_FLOWSPEC)
 | |
| 		bgp_fs_config_write_pbr(vty, bgp, afi, safi);
 | |
| 
 | |
| 	if (safi == SAFI_MPLS_VPN)
 | |
| 		bgp_vpn_config_write(vty, bgp, afi, safi);
 | |
| 
 | |
| 	if (safi == SAFI_UNICAST) {
 | |
| 		bgp_vpn_policy_config_write_afi(vty, bgp, afi);
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 			       BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
 | |
| 
 | |
| 			vty_out(vty, "  export vpn\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 			       BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
 | |
| 
 | |
| 			vty_out(vty, "  import vpn\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(bgp->af_flags[afi][safi],
 | |
| 			       BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
 | |
| 			char *name;
 | |
| 
 | |
| 			for (ALL_LIST_ELEMENTS_RO(
 | |
| 				     bgp->vpn_policy[afi].import_vrf, node,
 | |
| 				     name))
 | |
| 				vty_out(vty, "  import vrf %s\n", name);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	vty_endframe(vty, " exit-address-family\n");
 | |
| }
 | |
| 
 | |
| int bgp_config_write(struct vty *vty)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct peer_group *group;
 | |
| 	struct peer *peer;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct listnode *mnode, *mnnode;
 | |
| 	afi_t afi;
 | |
| 	safi_t safi;
 | |
| 	uint32_t tovpn_sid_index = 0;
 | |
| 
 | |
| 	if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
 | |
| 		vty_out(vty, "bgp route-map delay-timer %u\n",
 | |
| 			bm->rmap_update_timer);
 | |
| 
 | |
| 	if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) {
 | |
| 		vty_out(vty, "bgp update-delay %d", bm->v_update_delay);
 | |
| 		if (bm->v_update_delay != bm->v_establish_wait)
 | |
| 			vty_out(vty, " %d", bm->v_establish_wait);
 | |
| 		vty_out(vty, "\n");
 | |
| 	}
 | |
| 
 | |
| 	if (bm->wait_for_fib)
 | |
| 		vty_out(vty, "bgp suppress-fib-pending\n");
 | |
| 
 | |
| 	if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 		vty_out(vty, "bgp graceful-shutdown\n");
 | |
| 
 | |
| 	/* No-RIB (Zebra) option flag configuration */
 | |
| 	if (bgp_option_check(BGP_OPT_NO_FIB))
 | |
| 		vty_out(vty, "bgp no-rib\n");
 | |
| 
 | |
| 	if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA))
 | |
| 		vty_out(vty, "bgp send-extra-data zebra\n");
 | |
| 
 | |
| 	/* BGP session DSCP value */
 | |
| 	if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL)
 | |
| 		vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2);
 | |
| 
 | |
| 	/* BGP InQ limit */
 | |
| 	if (bm->inq_limit != BM_DEFAULT_Q_LIMIT)
 | |
| 		vty_out(vty, "bgp input-queue-limit %u\n", bm->inq_limit);
 | |
| 
 | |
| 	if (bm->outq_limit != BM_DEFAULT_Q_LIMIT)
 | |
| 		vty_out(vty, "bgp output-queue-limit %u\n", bm->outq_limit);
 | |
| 
 | |
| 	/* BGP configuration. */
 | |
| 	for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
 | |
| 
 | |
| 		/* skip all auto created vrf as they dont have user config */
 | |
| 		if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
 | |
| 			continue;
 | |
| 
 | |
| 		/* Router bgp ASN */
 | |
| 		vty_out(vty, "router bgp %s", bgp->as_pretty);
 | |
| 
 | |
| 		if (bgp->name)
 | |
| 			vty_out(vty, " %s %s",
 | |
| 				(bgp->inst_type  == BGP_INSTANCE_TYPE_VIEW)
 | |
| 				? "view" : "vrf", bgp->name);
 | |
| 		if (CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION))
 | |
| 			vty_out(vty, " as-notation %s",
 | |
| 				asn_mode2str(bgp->asnotation));
 | |
| 
 | |
| 		vty_out(vty, "\n");
 | |
| 
 | |
| 		/* BGP fast-external-failover. */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
 | |
| 			vty_out(vty, " no bgp fast-external-failover\n");
 | |
| 
 | |
| 		/* BGP router ID. */
 | |
| 		if (bgp->router_id_static.s_addr != INADDR_ANY)
 | |
| 			vty_out(vty, " bgp router-id %pI4\n",
 | |
| 				&bgp->router_id_static);
 | |
| 
 | |
| 		/* Suppress fib pending */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_FIB_PENDING))
 | |
| 			vty_out(vty, " bgp suppress-fib-pending\n");
 | |
| 
 | |
| 		/* BGP log-neighbor-changes. */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES)
 | |
| 		    != SAVE_BGP_LOG_NEIGHBOR_CHANGES)
 | |
| 			vty_out(vty, " %sbgp log-neighbor-changes\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_LOG_NEIGHBOR_CHANGES)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP configuration. */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_ALWAYS_COMPARE_MED))
 | |
| 			vty_out(vty, " bgp always-compare-med\n");
 | |
| 
 | |
| 		/* RFC8212 default eBGP policy. */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 		    != SAVE_BGP_EBGP_REQUIRES_POLICY)
 | |
| 			vty_out(vty, " %sbgp ebgp-requires-policy\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_EBGP_REQUIRES_POLICY)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV4_EXPLICIT_NULL) &&
 | |
| 		    !!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV6_EXPLICIT_NULL))
 | |
| 			vty_out(vty, " bgp labeled-unicast explicit-null\n");
 | |
| 		else if (!!CHECK_FLAG(bgp->flags,
 | |
| 				      BGP_FLAG_LU_IPV4_EXPLICIT_NULL))
 | |
| 			vty_out(vty,
 | |
| 				" bgp labeled-unicast ipv4-explicit-null\n");
 | |
| 		else if (!!CHECK_FLAG(bgp->flags,
 | |
| 				      BGP_FLAG_LU_IPV6_EXPLICIT_NULL))
 | |
| 			vty_out(vty,
 | |
| 				" bgp labeled-unicast ipv6-explicit-null\n");
 | |
| 
 | |
| 		/* draft-ietf-idr-deprecate-as-set-confed-set */
 | |
| 		if (bgp->reject_as_sets)
 | |
| 			vty_out(vty, " bgp reject-as-sets\n");
 | |
| 
 | |
| 		/* Suppress duplicate updates if the route actually not changed
 | |
| 		 */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
 | |
| 		    != SAVE_BGP_SUPPRESS_DUPLICATES)
 | |
| 			vty_out(vty, " %sbgp suppress-duplicates\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_SUPPRESS_DUPLICATES)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* Send Hard Reset CEASE Notification for 'Administrative Reset'
 | |
| 		 */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET) !=
 | |
| 		    SAVE_BGP_HARD_ADMIN_RESET)
 | |
| 			vty_out(vty, " %sbgp hard-administrative-reset\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_HARD_ADMIN_RESET)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP default <afi>-<safi> */
 | |
| 		FOREACH_AFI_SAFI (afi, safi) {
 | |
| 			if (afi == AFI_IP && safi == SAFI_UNICAST) {
 | |
| 				if (!bgp->default_af[afi][safi])
 | |
| 					vty_out(vty, " no bgp default %s\n",
 | |
| 						get_bgp_default_af_flag(afi,
 | |
| 									safi));
 | |
| 			} else if (bgp->default_af[afi][safi])
 | |
| 				vty_out(vty, " bgp default %s\n",
 | |
| 					get_bgp_default_af_flag(afi, safi));
 | |
| 		}
 | |
| 
 | |
| 		/* BGP default local-preference. */
 | |
| 		if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
 | |
| 			vty_out(vty, " bgp default local-preference %u\n",
 | |
| 				bgp->default_local_pref);
 | |
| 
 | |
| 		/* BGP default show-hostname */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SHOW_HOSTNAME)
 | |
| 		    != SAVE_BGP_SHOW_HOSTNAME)
 | |
| 			vty_out(vty, " %sbgp default show-hostname\n",
 | |
| 				CHECK_FLAG(bgp->flags, BGP_FLAG_SHOW_HOSTNAME)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP default show-nexthop-hostname */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME)
 | |
| 		    != SAVE_BGP_SHOW_HOSTNAME)
 | |
| 			vty_out(vty, " %sbgp default show-nexthop-hostname\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_SHOW_NEXTHOP_HOSTNAME)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP default subgroup-pkt-queue-max. */
 | |
| 		if (bgp->default_subgroup_pkt_queue_max
 | |
| 		    != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
 | |
| 			vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n",
 | |
| 				bgp->default_subgroup_pkt_queue_max);
 | |
| 
 | |
| 		/* BGP client-to-client reflection. */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT))
 | |
| 			vty_out(vty, " no bgp client-to-client reflection\n");
 | |
| 
 | |
| 		/* BGP cluster ID. */
 | |
| 		if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
 | |
| 			vty_out(vty, " bgp cluster-id %pI4\n",
 | |
| 				&bgp->cluster_id);
 | |
| 
 | |
| 		/* Disable ebgp connected nexthop check */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
 | |
| 			vty_out(vty,
 | |
| 				" bgp disable-ebgp-connected-route-check\n");
 | |
| 
 | |
| 		/* Confederation identifier*/
 | |
| 		if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
 | |
| 			vty_out(vty, " bgp confederation identifier %s\n",
 | |
| 				bgp->confed_id_pretty);
 | |
| 
 | |
| 		/* Confederation peer */
 | |
| 		if (bgp->confed_peers_cnt > 0) {
 | |
| 			int i;
 | |
| 
 | |
| 			vty_out(vty, " bgp confederation peers");
 | |
| 
 | |
| 			for (i = 0; i < bgp->confed_peers_cnt; i++)
 | |
| 				vty_out(vty, " %s",
 | |
| 					bgp->confed_peers[i].as_pretty);
 | |
| 
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		/* BGP deterministic-med. */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)
 | |
| 		    != SAVE_BGP_DETERMINISTIC_MED)
 | |
| 			vty_out(vty, " %sbgp deterministic-med\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_DETERMINISTIC_MED)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP update-delay. */
 | |
| 		bgp_config_write_update_delay(vty, bgp);
 | |
| 
 | |
| 		if (bgp->v_maxmed_onstartup
 | |
| 		    != BGP_MAXMED_ONSTARTUP_UNCONFIGURED) {
 | |
| 			vty_out(vty, " bgp max-med on-startup %u",
 | |
| 				bgp->v_maxmed_onstartup);
 | |
| 			if (bgp->maxmed_onstartup_value
 | |
| 			    != BGP_MAXMED_VALUE_DEFAULT)
 | |
| 				vty_out(vty, " %u",
 | |
| 					bgp->maxmed_onstartup_value);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 		if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED) {
 | |
| 			vty_out(vty, " bgp max-med administrative");
 | |
| 			if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT)
 | |
| 				vty_out(vty, " %u", bgp->maxmed_admin_value);
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		/* write quanta */
 | |
| 		bgp_config_write_wpkt_quanta(vty, bgp);
 | |
| 		/* read quanta */
 | |
| 		bgp_config_write_rpkt_quanta(vty, bgp);
 | |
| 
 | |
| 		/* coalesce time */
 | |
| 		bgp_config_write_coalesce_time(vty, bgp);
 | |
| 
 | |
| 		/* BGP per-instance graceful-shutdown */
 | |
| 		/* BGP-wide settings and per-instance settings are mutually
 | |
| 		 * exclusive.
 | |
| 		 */
 | |
| 		if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 			if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
 | |
| 				vty_out(vty, " bgp graceful-shutdown\n");
 | |
| 
 | |
| 		/* Long-lived Graceful Restart */
 | |
| 		if (bgp->llgr_stale_time != BGP_DEFAULT_LLGR_STALE_TIME)
 | |
| 			vty_out(vty,
 | |
| 				" bgp long-lived-graceful-restart stale-time %u\n",
 | |
| 				bgp->llgr_stale_time);
 | |
| 
 | |
| 		/* BGP graceful-restart. */
 | |
| 		if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
 | |
| 			vty_out(vty,
 | |
| 				" bgp graceful-restart stalepath-time %u\n",
 | |
| 				bgp->stalepath_time);
 | |
| 
 | |
| 		if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
 | |
| 			vty_out(vty, " bgp graceful-restart restart-time %u\n",
 | |
| 				bgp->restart_time);
 | |
| 
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION) !=
 | |
| 		    SAVE_BGP_GRACEFUL_NOTIFICATION)
 | |
| 			vty_out(vty, " %sbgp graceful-restart notification\n",
 | |
| 				CHECK_FLAG(bgp->flags,
 | |
| 					   BGP_FLAG_GRACEFUL_NOTIFICATION)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME)
 | |
| 			vty_out(vty,
 | |
| 				" bgp graceful-restart select-defer-time %u\n",
 | |
| 				bgp->select_defer_time);
 | |
| 
 | |
| 		if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR)
 | |
| 			vty_out(vty, " bgp graceful-restart\n");
 | |
| 
 | |
| 		if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE)
 | |
| 			vty_out(vty, " bgp graceful-restart-disable\n");
 | |
| 
 | |
| 		/* BGP graceful-restart Preserve State F bit. */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD))
 | |
| 			vty_out(vty,
 | |
| 				" bgp graceful-restart preserve-fw-state\n");
 | |
| 
 | |
| 		/* BGP TCP keepalive */
 | |
| 		bgp_config_tcp_keepalive(vty, bgp);
 | |
| 
 | |
| 		/* Stale timer for RIB */
 | |
| 		if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
 | |
| 			vty_out(vty,
 | |
| 				" bgp graceful-restart rib-stale-time %u\n",
 | |
| 				bgp->rib_stale_time);
 | |
| 
 | |
| 		/* BGP bestpath method. */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE))
 | |
| 			vty_out(vty, " bgp bestpath as-path ignore\n");
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED))
 | |
| 			vty_out(vty, " bgp bestpath as-path confed\n");
 | |
| 
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
 | |
| 			if (CHECK_FLAG(bgp->flags,
 | |
| 				       BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
 | |
| 				vty_out(vty,
 | |
| 					" bgp bestpath as-path multipath-relax as-set\n");
 | |
| 			} else {
 | |
| 				vty_out(vty,
 | |
| 					" bgp bestpath as-path multipath-relax\n");
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
 | |
| 			vty_out(vty,
 | |
| 				" bgp route-reflector allow-outbound-policy\n");
 | |
| 		}
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
 | |
| 			vty_out(vty, " bgp bestpath compare-routerid\n");
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP))
 | |
| 			vty_out(vty, " bgp bestpath aigp\n");
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
 | |
| 		    || CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
 | |
| 			vty_out(vty, " bgp bestpath med");
 | |
| 			if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED))
 | |
| 				vty_out(vty, " confed");
 | |
| 			if (CHECK_FLAG(bgp->flags,
 | |
| 				       BGP_FLAG_MED_MISSING_AS_WORST))
 | |
| 				vty_out(vty, " missing-as-worst");
 | |
| 			vty_out(vty, "\n");
 | |
| 		}
 | |
| 
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
 | |
| 			vty_out(vty,
 | |
| 				" bgp bestpath peer-type multipath-relax\n");
 | |
| 
 | |
| 		/* Link bandwidth handling. */
 | |
| 		if (bgp->lb_handling == BGP_LINK_BW_IGNORE_BW)
 | |
| 			vty_out(vty, " bgp bestpath bandwidth ignore\n");
 | |
| 		else if (bgp->lb_handling == BGP_LINK_BW_SKIP_MISSING)
 | |
| 			vty_out(vty, " bgp bestpath bandwidth skip-missing\n");
 | |
| 		else if (bgp->lb_handling == BGP_LINK_BW_DEFWT_4_MISSING)
 | |
| 			vty_out(vty, " bgp bestpath bandwidth default-weight-for-missing\n");
 | |
| 
 | |
| 		/* BGP network import check. */
 | |
| 		if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)
 | |
| 		    != SAVE_BGP_IMPORT_CHECK)
 | |
| 			vty_out(vty, " %sbgp network import-check\n",
 | |
| 				CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)
 | |
| 					? ""
 | |
| 					: "no ");
 | |
| 
 | |
| 		/* BGP timers configuration. */
 | |
| 		if (bgp->default_keepalive != SAVE_BGP_KEEPALIVE
 | |
| 		    || bgp->default_holdtime != SAVE_BGP_HOLDTIME)
 | |
| 			vty_out(vty, " timers bgp %u %u\n",
 | |
| 				bgp->default_keepalive, bgp->default_holdtime);
 | |
| 
 | |
| 		/* BGP minimum holdtime configuration. */
 | |
| 		if (bgp->default_min_holdtime != SAVE_BGP_HOLDTIME
 | |
| 		    && bgp->default_min_holdtime != 0)
 | |
| 			vty_out(vty, " bgp minimum-holdtime %u\n",
 | |
| 				bgp->default_min_holdtime);
 | |
| 
 | |
| 		/* Conditional advertisement timer configuration */
 | |
| 		if (bgp->condition_check_period
 | |
| 		    != DEFAULT_CONDITIONAL_ROUTES_POLL_TIME)
 | |
| 			vty_out(vty,
 | |
| 				" bgp conditional-advertisement timer %u\n",
 | |
| 				bgp->condition_check_period);
 | |
| 
 | |
| 		/* default-originate timer configuration */
 | |
| 		if (bgp->rmap_def_originate_eval_timer !=
 | |
| 		    RMAP_DEFAULT_ORIGINATE_EVAL_TIMER)
 | |
| 			vty_out(vty, " bgp default-originate timer %u\n",
 | |
| 				bgp->rmap_def_originate_eval_timer);
 | |
| 
 | |
| 		/* peer-group */
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
 | |
| 			bgp_config_write_peer_global(vty, bgp, group->conf);
 | |
| 		}
 | |
| 
 | |
| 		/* Normal neighbor configuration. */
 | |
| 		for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 | |
| 			if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
 | |
| 				bgp_config_write_peer_global(vty, bgp, peer);
 | |
| 		}
 | |
| 
 | |
| 		/* listen range and limit for dynamic BGP neighbors */
 | |
| 		bgp_config_write_listen(vty, bgp);
 | |
| 
 | |
| 		/*
 | |
| 		 * BGP default autoshutdown neighbors
 | |
| 		 *
 | |
| 		 * This must be placed after any peer and peer-group
 | |
| 		 * configuration, to avoid setting all peers to shutdown after
 | |
| 		 * a daemon restart, which is undesired behavior. (see #2286)
 | |
| 		 */
 | |
| 		if (bgp->autoshutdown)
 | |
| 			vty_out(vty, " bgp default shutdown\n");
 | |
| 
 | |
| 		/* BGP instance administrative shutdown */
 | |
| 		if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
 | |
| 			vty_out(vty, " bgp shutdown\n");
 | |
| 
 | |
| 		if (bgp->allow_martian)
 | |
| 			vty_out(vty, " bgp allow-martian-nexthop\n");
 | |
| 
 | |
| 		if (bgp->fast_convergence)
 | |
| 			vty_out(vty, " bgp fast-convergence\n");
 | |
| 
 | |
| 		if (bgp->srv6_enabled) {
 | |
| 			vty_frame(vty, " !\n segment-routing srv6\n");
 | |
| 			if (strlen(bgp->srv6_locator_name))
 | |
| 				vty_out(vty, "  locator %s\n",
 | |
| 					bgp->srv6_locator_name);
 | |
| 			vty_endframe(vty, " exit\n");
 | |
| 		}
 | |
| 
 | |
| 		tovpn_sid_index = bgp->tovpn_sid_index;
 | |
| 		if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)) {
 | |
| 			vty_out(vty, " sid vpn per-vrf export auto\n");
 | |
| 		} else if (tovpn_sid_index != 0) {
 | |
| 			vty_out(vty, " sid vpn per-vrf export %d\n",
 | |
| 				tovpn_sid_index);
 | |
| 		}
 | |
| 
 | |
| 		/* IPv4 unicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
 | |
| 
 | |
| 		/* IPv4 multicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MULTICAST);
 | |
| 
 | |
| 		/* IPv4 labeled-unicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_LABELED_UNICAST);
 | |
| 
 | |
| 		/* IPv4 VPN configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MPLS_VPN);
 | |
| 
 | |
| 		/* ENCAPv4 configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP);
 | |
| 
 | |
| 		/* FLOWSPEC v4 configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP, SAFI_FLOWSPEC);
 | |
| 
 | |
| 		/* IPv6 unicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST);
 | |
| 
 | |
| 		/* IPv6 multicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MULTICAST);
 | |
| 
 | |
| 		/* IPv6 labeled-unicast configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6,
 | |
| 					SAFI_LABELED_UNICAST);
 | |
| 
 | |
| 		/* IPv6 VPN configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MPLS_VPN);
 | |
| 
 | |
| 		/* ENCAPv6 configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP);
 | |
| 
 | |
| 		/* FLOWSPEC v6 configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_FLOWSPEC);
 | |
| 
 | |
| 		/* EVPN configuration.  */
 | |
| 		bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN);
 | |
| 
 | |
| 		hook_call(bgp_inst_config_write, bgp, vty);
 | |
| 
 | |
| #ifdef ENABLE_BGP_VNC
 | |
| 		bgp_rfapi_cfg_write(vty, bgp);
 | |
| #endif
 | |
| 
 | |
| 		vty_out(vty, "exit\n");
 | |
| 		vty_out(vty, "!\n");
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* BGP node structure. */
 | |
| static struct cmd_node bgp_node = {
 | |
| 	.name = "bgp",
 | |
| 	.node = BGP_NODE,
 | |
| 	.parent_node = CONFIG_NODE,
 | |
| 	.prompt = "%s(config-router)# ",
 | |
| 	.config_write = bgp_config_write,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv4_unicast_node = {
 | |
| 	.name = "bgp ipv4 unicast",
 | |
| 	.node = BGP_IPV4_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv4_multicast_node = {
 | |
| 	.name = "bgp ipv4 multicast",
 | |
| 	.node = BGP_IPV4M_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv4_labeled_unicast_node = {
 | |
| 	.name = "bgp ipv4 labeled unicast",
 | |
| 	.node = BGP_IPV4L_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv6_unicast_node = {
 | |
| 	.name = "bgp ipv6 unicast",
 | |
| 	.node = BGP_IPV6_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv6_multicast_node = {
 | |
| 	.name = "bgp ipv6 multicast",
 | |
| 	.node = BGP_IPV6M_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_ipv6_labeled_unicast_node = {
 | |
| 	.name = "bgp ipv6 labeled unicast",
 | |
| 	.node = BGP_IPV6L_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_vpnv4_node = {
 | |
| 	.name = "bgp vpnv4",
 | |
| 	.node = BGP_VPNV4_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_vpnv6_node = {
 | |
| 	.name = "bgp vpnv6",
 | |
| 	.node = BGP_VPNV6_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af-vpnv6)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_evpn_node = {
 | |
| 	.name = "bgp evpn",
 | |
| 	.node = BGP_EVPN_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-evpn)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_evpn_vni_node = {
 | |
| 	.name = "bgp evpn vni",
 | |
| 	.node = BGP_EVPN_VNI_NODE,
 | |
| 	.parent_node = BGP_EVPN_NODE,
 | |
| 	.prompt = "%s(config-router-af-vni)# ",
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_flowspecv4_node = {
 | |
| 	.name = "bgp ipv4 flowspec",
 | |
| 	.node = BGP_FLOWSPECV4_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_flowspecv6_node = {
 | |
| 	.name = "bgp ipv6 flowspec",
 | |
| 	.node = BGP_FLOWSPECV6_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-af-vpnv6)# ",
 | |
| 	.no_xpath = true,
 | |
| };
 | |
| 
 | |
| static struct cmd_node bgp_srv6_node = {
 | |
| 	.name = "bgp srv6",
 | |
| 	.node = BGP_SRV6_NODE,
 | |
| 	.parent_node = BGP_NODE,
 | |
| 	.prompt = "%s(config-router-srv6)# ",
 | |
| };
 | |
| 
 | |
| static void community_list_vty(void);
 | |
| 
 | |
| static void bgp_ac_peergroup(vector comps, struct cmd_token *token)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct peer_group *group;
 | |
| 	struct listnode *lnbgp, *lnpeer;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) {
 | |
| 		for (ALL_LIST_ELEMENTS_RO(bgp->group, lnpeer, group))
 | |
| 			vector_set(comps,
 | |
| 				   XSTRDUP(MTYPE_COMPLETION, group->name));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_ac_peer(vector comps, struct cmd_token *token)
 | |
| {
 | |
| 	struct bgp *bgp;
 | |
| 	struct peer *peer;
 | |
| 	struct listnode *lnbgp, *lnpeer;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) {
 | |
| 		for (ALL_LIST_ELEMENTS_RO(bgp->peer, lnpeer, peer)) {
 | |
| 			/* only provide suggestions on the appropriate input
 | |
| 			 * token type,
 | |
| 			 * they'll otherwise show up multiple times */
 | |
| 			enum cmd_token_type match_type;
 | |
| 			char *name = peer->host;
 | |
| 
 | |
| 			if (peer->conf_if) {
 | |
| 				match_type = VARIABLE_TKN;
 | |
| 				name = peer->conf_if;
 | |
| 			} else if (strchr(peer->host, ':'))
 | |
| 				match_type = IPV6_TKN;
 | |
| 			else
 | |
| 				match_type = IPV4_TKN;
 | |
| 
 | |
| 			if (token->type != match_type)
 | |
| 				continue;
 | |
| 
 | |
| 			vector_set(comps, XSTRDUP(MTYPE_COMPLETION, name));
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void bgp_ac_neighbor(vector comps, struct cmd_token *token)
 | |
| {
 | |
| 	bgp_ac_peer(comps, token);
 | |
| 
 | |
| 	if (token->type == VARIABLE_TKN)
 | |
| 		bgp_ac_peergroup(comps, token);
 | |
| }
 | |
| 
 | |
| static const struct cmd_variable_handler bgp_var_neighbor[] = {
 | |
| 	{.varname = "neighbor", .completions = bgp_ac_neighbor},
 | |
| 	{.varname = "neighbors", .completions = bgp_ac_neighbor},
 | |
| 	{.varname = "peer", .completions = bgp_ac_neighbor},
 | |
| 	{.completions = NULL}};
 | |
| 
 | |
| static const struct cmd_variable_handler bgp_var_peergroup[] = {
 | |
| 	{.tokenname = "PGNAME", .completions = bgp_ac_peergroup},
 | |
| 	{.completions = NULL} };
 | |
| 
 | |
| DEFINE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp));
 | |
| 
 | |
| static struct event *t_bgp_cfg;
 | |
| 
 | |
| bool bgp_config_inprocess(void)
 | |
| {
 | |
| 	return event_is_scheduled(t_bgp_cfg);
 | |
| }
 | |
| 
 | |
| /* Max wait time for config to load before post-config processing */
 | |
| #define BGP_PRE_CONFIG_MAX_WAIT_SECONDS 600
 | |
| 
 | |
| static void bgp_config_finish(struct event *t)
 | |
| {
 | |
| 	struct listnode *node;
 | |
| 	struct bgp *bgp;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp))
 | |
| 		hook_call(bgp_config_end, bgp);
 | |
| }
 | |
| 
 | |
| static void bgp_config_end_timeout(struct event *t)
 | |
| {
 | |
| 	zlog_err("BGP configuration end timer expired after %d seconds.",
 | |
| 		 BGP_PRE_CONFIG_MAX_WAIT_SECONDS);
 | |
| 	bgp_config_finish(t);
 | |
| }
 | |
| 
 | |
| static void bgp_config_start(void)
 | |
| {
 | |
| 	EVENT_OFF(t_bgp_cfg);
 | |
| 	event_add_timer(bm->master, bgp_config_end_timeout, NULL,
 | |
| 			BGP_PRE_CONFIG_MAX_WAIT_SECONDS, &t_bgp_cfg);
 | |
| }
 | |
| 
 | |
| /* When we receive a hook the configuration is read,
 | |
|  * we start a timer to make sure we postpone sending
 | |
|  * EoR before route-maps are processed.
 | |
|  * This is especially valid if using `bgp route-map delay-timer`.
 | |
|  */
 | |
| static void bgp_config_end(void)
 | |
| {
 | |
| #define BGP_POST_CONFIG_DELAY_SECONDS 1
 | |
| 	uint32_t bgp_post_config_delay =
 | |
| 		event_is_scheduled(bm->t_rmap_update)
 | |
| 			? event_timer_remain_second(bm->t_rmap_update)
 | |
| 			: BGP_POST_CONFIG_DELAY_SECONDS;
 | |
| 
 | |
| 	/* If BGP config processing thread isn't running, then
 | |
| 	 * we can return and rely it's properly handled.
 | |
| 	 */
 | |
| 	if (!bgp_config_inprocess())
 | |
| 		return;
 | |
| 
 | |
| 	EVENT_OFF(t_bgp_cfg);
 | |
| 
 | |
| 	/* Start a new timer to make sure we don't send EoR
 | |
| 	 * before route-maps are processed.
 | |
| 	 */
 | |
| 	event_add_timer(bm->master, bgp_config_finish, NULL,
 | |
| 			bgp_post_config_delay, &t_bgp_cfg);
 | |
| }
 | |
| 
 | |
| static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
 | |
| {
 | |
| 	int write = 0;
 | |
| 	struct interface *ifp;
 | |
| 	struct bgp_interface *iifp;
 | |
| 
 | |
| 	FOR_ALL_INTERFACES (vrf, ifp) {
 | |
| 		iifp = ifp->info;
 | |
| 		if (!iifp)
 | |
| 			continue;
 | |
| 
 | |
| 		if_vty_config_start(vty, ifp);
 | |
| 
 | |
| 		if (CHECK_FLAG(iifp->flags,
 | |
| 			       BGP_INTERFACE_MPLS_BGP_FORWARDING)) {
 | |
| 			vty_out(vty, " mpls bgp forwarding\n");
 | |
| 			write++;
 | |
| 		}
 | |
| 		if (CHECK_FLAG(iifp->flags,
 | |
| 			       BGP_INTERFACE_MPLS_L3VPN_SWITCHING)) {
 | |
| 			vty_out(vty,
 | |
| 				" mpls bgp l3vpn-multi-domain-switching\n");
 | |
| 			write++;
 | |
| 		}
 | |
| 
 | |
| 		if_vty_config_end(vty);
 | |
| 	}
 | |
| 
 | |
| 	return write;
 | |
| }
 | |
| 
 | |
| /* Configuration write function for bgpd. */
 | |
| static int config_write_interface(struct vty *vty)
 | |
| {
 | |
| 	int write = 0;
 | |
| 	struct vrf *vrf = NULL;
 | |
| 
 | |
| 	/* Display all VRF aware OSPF interface configuration */
 | |
| 	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | |
| 		write += config_write_interface_one(vty, vrf);
 | |
| 	}
 | |
| 
 | |
| 	return write;
 | |
| }
 | |
| 
 | |
| DEFPY(mpls_bgp_forwarding, mpls_bgp_forwarding_cmd,
 | |
|       "[no$no] mpls bgp forwarding",
 | |
|       NO_STR MPLS_STR BGP_STR
 | |
|       "Enable MPLS forwarding for eBGP directly connected peers\n")
 | |
| {
 | |
| 	bool check;
 | |
| 	struct bgp_interface *iifp;
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(interface, ifp);
 | |
| 	iifp = ifp->info;
 | |
| 	if (!iifp) {
 | |
| 		vty_out(vty, "Interface %s not available\n", ifp->name);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	check = CHECK_FLAG(iifp->flags, BGP_INTERFACE_MPLS_BGP_FORWARDING);
 | |
| 	if (check != !no) {
 | |
| 		if (no)
 | |
| 			UNSET_FLAG(iifp->flags,
 | |
| 				   BGP_INTERFACE_MPLS_BGP_FORWARDING);
 | |
| 		else
 | |
| 			SET_FLAG(iifp->flags,
 | |
| 				 BGP_INTERFACE_MPLS_BGP_FORWARDING);
 | |
| 		/* trigger a nht update on eBGP sessions */
 | |
| 		if (if_is_operative(ifp))
 | |
| 			bgp_nht_ifp_up(ifp);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY(mpls_bgp_l3vpn_multi_domain_switching,
 | |
|       mpls_bgp_l3vpn_multi_domain_switching_cmd,
 | |
|       "[no$no] mpls bgp l3vpn-multi-domain-switching",
 | |
|       NO_STR MPLS_STR BGP_STR
 | |
|       "Bind a local MPLS label to incoming L3VPN updates\n")
 | |
| {
 | |
| 	bool check;
 | |
| 	struct bgp_interface *iifp;
 | |
| 
 | |
| 	VTY_DECLVAR_CONTEXT(interface, ifp);
 | |
| 	iifp = ifp->info;
 | |
| 	if (!iifp) {
 | |
| 		vty_out(vty, "Interface %s not available\n", ifp->name);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	check = CHECK_FLAG(iifp->flags, BGP_INTERFACE_MPLS_L3VPN_SWITCHING);
 | |
| 	if (check == !no)
 | |
| 		return CMD_SUCCESS;
 | |
| 	if (no)
 | |
| 		UNSET_FLAG(iifp->flags, BGP_INTERFACE_MPLS_L3VPN_SWITCHING);
 | |
| 	else
 | |
| 		SET_FLAG(iifp->flags, BGP_INTERFACE_MPLS_L3VPN_SWITCHING);
 | |
| 	/* trigger a nht update on eBGP sessions */
 | |
| 	if (if_is_operative(ifp))
 | |
| 		bgp_nht_ifp_up(ifp);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_inq_limit,
 | |
|        bgp_inq_limit_cmd,
 | |
|        "bgp input-queue-limit (1-4294967295)$limit",
 | |
|        BGP_STR
 | |
|        "Set the BGP Input Queue limit for all peers when message parsing\n"
 | |
|        "Input-Queue limit\n")
 | |
| {
 | |
| 	bm->inq_limit = limit;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_inq_limit,
 | |
|        no_bgp_inq_limit_cmd,
 | |
|        "no bgp input-queue-limit [(1-4294967295)$limit]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Set the BGP Input Queue limit for all peers when message parsing\n"
 | |
|        "Input-Queue limit\n")
 | |
| {
 | |
| 	bm->inq_limit = BM_DEFAULT_Q_LIMIT;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (bgp_outq_limit,
 | |
|        bgp_outq_limit_cmd,
 | |
|        "bgp output-queue-limit (1-4294967295)$limit",
 | |
|        BGP_STR
 | |
|        "Set the BGP Output Queue limit for all peers when message parsing\n"
 | |
|        "Output-Queue limit\n")
 | |
| {
 | |
| 	bm->outq_limit = limit;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFPY (no_bgp_outq_limit,
 | |
|        no_bgp_outq_limit_cmd,
 | |
|        "no bgp output-queue-limit [(1-4294967295)$limit]",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        "Set the BGP Output Queue limit for all peers when message parsing\n"
 | |
|        "Output-Queue limit\n")
 | |
| {
 | |
| 	bm->outq_limit = BM_DEFAULT_Q_LIMIT;
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Initialization of BGP interface. */
 | |
| static void bgp_vty_if_init(void)
 | |
| {
 | |
| 	/* Install interface node. */
 | |
| 	if_cmd_init(config_write_interface);
 | |
| 
 | |
| 	/* "mpls bgp forwarding" commands. */
 | |
| 	install_element(INTERFACE_NODE, &mpls_bgp_forwarding_cmd);
 | |
| 	install_element(INTERFACE_NODE,
 | |
| 			&mpls_bgp_l3vpn_multi_domain_switching_cmd);
 | |
| }
 | |
| 
 | |
| void bgp_vty_init(void)
 | |
| {
 | |
| 	cmd_variable_handler_register(bgp_var_neighbor);
 | |
| 	cmd_variable_handler_register(bgp_var_peergroup);
 | |
| 
 | |
| 	cmd_init_config_callbacks(bgp_config_start, bgp_config_end);
 | |
| 
 | |
| 	/* Install bgp top node. */
 | |
| 	install_node(&bgp_node);
 | |
| 	install_node(&bgp_ipv4_unicast_node);
 | |
| 	install_node(&bgp_ipv4_multicast_node);
 | |
| 	install_node(&bgp_ipv4_labeled_unicast_node);
 | |
| 	install_node(&bgp_ipv6_unicast_node);
 | |
| 	install_node(&bgp_ipv6_multicast_node);
 | |
| 	install_node(&bgp_ipv6_labeled_unicast_node);
 | |
| 	install_node(&bgp_vpnv4_node);
 | |
| 	install_node(&bgp_vpnv6_node);
 | |
| 	install_node(&bgp_evpn_node);
 | |
| 	install_node(&bgp_evpn_vni_node);
 | |
| 	install_node(&bgp_flowspecv4_node);
 | |
| 	install_node(&bgp_flowspecv6_node);
 | |
| 	install_node(&bgp_srv6_node);
 | |
| 
 | |
| 	/* Install default VTY commands to new nodes.  */
 | |
| 	install_default(BGP_NODE);
 | |
| 	install_default(BGP_IPV4_NODE);
 | |
| 	install_default(BGP_IPV4M_NODE);
 | |
| 	install_default(BGP_IPV4L_NODE);
 | |
| 	install_default(BGP_IPV6_NODE);
 | |
| 	install_default(BGP_IPV6M_NODE);
 | |
| 	install_default(BGP_IPV6L_NODE);
 | |
| 	install_default(BGP_VPNV4_NODE);
 | |
| 	install_default(BGP_VPNV6_NODE);
 | |
| 	install_default(BGP_FLOWSPECV4_NODE);
 | |
| 	install_default(BGP_FLOWSPECV6_NODE);
 | |
| 	install_default(BGP_EVPN_NODE);
 | |
| 	install_default(BGP_EVPN_VNI_NODE);
 | |
| 	install_default(BGP_SRV6_NODE);
 | |
| 
 | |
| 	/* "global bgp inq-limit command */
 | |
| 	install_element(CONFIG_NODE, &bgp_inq_limit_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_inq_limit_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_outq_limit_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_outq_limit_cmd);
 | |
| 
 | |
| 	/* "bgp local-mac" hidden commands. */
 | |
| 	install_element(CONFIG_NODE, &bgp_local_mac_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_local_mac_cmd);
 | |
| 
 | |
| 	/* "bgp suppress-fib-pending" global */
 | |
| 	install_element(CONFIG_NODE, &bgp_global_suppress_fib_pending_cmd);
 | |
| 
 | |
| 	/* bgp route-map delay-timer commands. */
 | |
| 	install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd);
 | |
| 
 | |
| 	install_element(BGP_NODE, &bgp_allow_martian_cmd);
 | |
| 
 | |
| 	/* bgp fast-convergence command */
 | |
| 	install_element(BGP_NODE, &bgp_fast_convergence_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_fast_convergence_cmd);
 | |
| 
 | |
| 	/* global bgp update-delay command */
 | |
| 	install_element(CONFIG_NODE, &bgp_global_update_delay_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd);
 | |
| 
 | |
| 	/* global bgp graceful-shutdown command */
 | |
| 	install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd);
 | |
| 
 | |
| 	/* Dummy commands (Currently not supported) */
 | |
| 	install_element(BGP_NODE, &no_synchronization_cmd);
 | |
| 	install_element(BGP_NODE, &no_auto_summary_cmd);
 | |
| 
 | |
| 	/* "router bgp" commands. */
 | |
| 	install_element(CONFIG_NODE, &router_bgp_cmd);
 | |
| 
 | |
| 	/* "no router bgp" commands. */
 | |
| 	install_element(CONFIG_NODE, &no_router_bgp_cmd);
 | |
| 
 | |
| 	/* "bgp session-dscp command */
 | |
| 	install_element(CONFIG_NODE, &bgp_session_dscp_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_session_dscp_cmd);
 | |
| 
 | |
| 	/* "bgp router-id" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_router_id_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_router_id_cmd);
 | |
| 
 | |
| 	/* "bgp suppress-fib-pending" command */
 | |
| 	install_element(BGP_NODE, &bgp_suppress_fib_pending_cmd);
 | |
| 
 | |
| 	/* "bgp cluster-id" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_cluster_id_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_cluster_id_cmd);
 | |
| 
 | |
| 	/* "bgp no-rib" commands. */
 | |
| 	install_element(CONFIG_NODE, &bgp_norib_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_norib_cmd);
 | |
| 
 | |
| 	install_element(CONFIG_NODE, &no_bgp_send_extra_data_cmd);
 | |
| 
 | |
| 	/* "bgp confederation" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_confederation_identifier_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_confederation_identifier_cmd);
 | |
| 
 | |
| 	/* "bgp confederation peers" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_confederation_peers_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_confederation_peers_cmd);
 | |
| 
 | |
| 	/* bgp max-med command */
 | |
| 	install_element(BGP_NODE, &bgp_maxmed_admin_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_maxmed_admin_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_maxmed_admin_medv_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_maxmed_onstartup_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_maxmed_onstartup_cmd);
 | |
| 
 | |
| 	/* "neighbor role" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_role_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_role_strict_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_role_cmd);
 | |
| 
 | |
| 	/* "neighbor aigp" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_aigp_cmd);
 | |
| 
 | |
| 	/* "neighbor graceful-shutdown" command */
 | |
| 	install_element(BGP_NODE, &neighbor_graceful_shutdown_cmd);
 | |
| 
 | |
| 	/* bgp disable-ebgp-connected-nh-check */
 | |
| 	install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
 | |
| 
 | |
| 	/* bgp update-delay command */
 | |
| 	install_element(BGP_NODE, &bgp_update_delay_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_update_delay_cmd);
 | |
| 
 | |
| 	install_element(BGP_NODE, &bgp_wpkt_quanta_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_rpkt_quanta_cmd);
 | |
| 
 | |
| 	install_element(BGP_NODE, &bgp_coalesce_time_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_coalesce_time_cmd);
 | |
| 
 | |
| 	/* "maximum-paths" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_maxpaths_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_maxpaths_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_maxpaths_ibgp_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_maxpaths_ibgp_cluster_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_maxpaths_ibgp_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd);
 | |
| 
 | |
| 	install_element(BGP_IPV4L_NODE, &bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_bgp_maxpaths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd);
 | |
| 
 | |
| 	/* "timers bgp" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_timers_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_timers_cmd);
 | |
| 
 | |
| 	/* "minimum-holdtime" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_minimum_holdtime_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_minimum_holdtime_cmd);
 | |
| 
 | |
| 	/* route-map delay-timer commands - per instance for backwards compat.
 | |
| 	 */
 | |
| 	install_element(BGP_NODE, &bgp_set_route_map_delay_timer_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_set_route_map_delay_timer_cmd);
 | |
| 
 | |
| 	/* "bgp client-to-client reflection" commands */
 | |
| 	install_element(BGP_NODE, &no_bgp_client_to_client_reflection_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_client_to_client_reflection_cmd);
 | |
| 
 | |
| 	/* "bgp always-compare-med" commands */
 | |
| 	install_element(BGP_NODE, &bgp_always_compare_med_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_always_compare_med_cmd);
 | |
| 
 | |
| 	/* bgp ebgp-requires-policy */
 | |
| 	install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd);
 | |
| 
 | |
| 	/* bgp labeled-unicast explicit-null */
 | |
| 	install_element(BGP_NODE, &bgp_lu_uses_explicit_null_cmd);
 | |
| 
 | |
| 	/* bgp suppress-duplicates */
 | |
| 	install_element(BGP_NODE, &bgp_suppress_duplicates_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_suppress_duplicates_cmd);
 | |
| 
 | |
| 	/* bgp reject-as-sets */
 | |
| 	install_element(BGP_NODE, &bgp_reject_as_sets_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_reject_as_sets_cmd);
 | |
| 
 | |
| 	/* "bgp deterministic-med" commands */
 | |
| 	install_element(BGP_NODE, &bgp_deterministic_med_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_deterministic_med_cmd);
 | |
| 
 | |
| 	/* "bgp graceful-restart" command */
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_cmd);
 | |
| 
 | |
| 	/* "bgp graceful-restart-disable" command */
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_disable_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_disable_cmd);
 | |
| 
 | |
| 	/* "neighbor a:b:c:d graceful-restart" command */
 | |
| 	install_element(BGP_NODE, &bgp_neighbor_graceful_restart_set_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_neighbor_graceful_restart_set_cmd);
 | |
| 
 | |
| 	/* "neighbor a:b:c:d graceful-restart-disable" command */
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_neighbor_graceful_restart_disable_set_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_bgp_neighbor_graceful_restart_disable_set_cmd);
 | |
| 
 | |
| 	/* "neighbor a:b:c:d graceful-restart-helper" command */
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_neighbor_graceful_restart_helper_set_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_bgp_neighbor_graceful_restart_helper_set_cmd);
 | |
| 
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_restart_time_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_select_defer_time_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_bgp_graceful_restart_select_defer_time_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_notification_cmd);
 | |
| 
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_disable_eor_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_disable_eor_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_graceful_restart_rib_stale_time_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_restart_rib_stale_time_cmd);
 | |
| 
 | |
| 	/* "bgp graceful-shutdown" commands */
 | |
| 	install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
 | |
| 
 | |
| 	/* "bgp hard-administrative-reset" commands */
 | |
| 	install_element(BGP_NODE, &bgp_administrative_reset_cmd);
 | |
| 
 | |
| 	/* "bgp long-lived-graceful-restart" commands */
 | |
| 	install_element(BGP_NODE, &bgp_llgr_stalepath_time_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_llgr_stalepath_time_cmd);
 | |
| 
 | |
| 	/* "bgp fast-external-failover" commands */
 | |
| 	install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath aigp" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_aigp_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath compare-routerid" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath as-path ignore" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_aspath_ignore_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath as-path confed" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_aspath_confed_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath as-path multipath-relax" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath peer-type multipath-relax" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_peer_type_multipath_relax_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_bgp_bestpath_peer_type_multipath_relax_cmd);
 | |
| 
 | |
| 	/* "bgp log-neighbor-changes" commands */
 | |
| 	install_element(BGP_NODE, &bgp_log_neighbor_changes_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_log_neighbor_changes_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath med" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_med_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_med_cmd);
 | |
| 
 | |
| 	/* "bgp bestpath bandwidth" commands */
 | |
| 	install_element(BGP_NODE, &bgp_bestpath_bw_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_bestpath_bw_cmd);
 | |
| 
 | |
| 	/* "no bgp default <afi>-<safi>" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_default_afi_safi_cmd);
 | |
| 
 | |
| 	/* "bgp network import-check" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_network_import_check_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_network_import_check_exact_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_network_import_check_cmd);
 | |
| 
 | |
| 	/* "bgp default local-preference" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_default_local_preference_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_default_local_preference_cmd);
 | |
| 
 | |
| 	/* bgp default show-hostname */
 | |
| 	install_element(BGP_NODE, &bgp_default_show_hostname_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_default_show_hostname_cmd);
 | |
| 
 | |
| 	/* bgp default show-nexthop-hostname */
 | |
| 	install_element(BGP_NODE, &bgp_default_show_nexthop_hostname_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_default_show_nexthop_hostname_cmd);
 | |
| 
 | |
| 	/* "bgp default subgroup-pkt-queue-max" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd);
 | |
| 
 | |
| 	/* bgp ibgp-allow-policy-mods command */
 | |
| 	install_element(BGP_NODE, &bgp_rr_allow_outbound_policy_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd);
 | |
| 
 | |
| 	/* "bgp listen limit" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_listen_limit_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_listen_limit_cmd);
 | |
| 
 | |
| 	/* "bgp listen range" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_listen_range_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_listen_range_cmd);
 | |
| 
 | |
| 	/* "bgp default shutdown" command */
 | |
| 	install_element(BGP_NODE, &bgp_default_shutdown_cmd);
 | |
| 
 | |
| 	/* "bgp shutdown" commands */
 | |
| 	install_element(BGP_NODE, &bgp_shutdown_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_shutdown_msg_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_shutdown_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_shutdown_msg_cmd);
 | |
| 
 | |
| 	/* "neighbor remote-as" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_remote_as_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_interface_config_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_interface_config_v6only_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_interface_config_remote_as_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_interface_v6only_config_remote_as_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_interface_config_cmd);
 | |
| 
 | |
| 	/* "neighbor peer-group" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_peer_group_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_peer_group_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_interface_peer_group_remote_as_cmd);
 | |
| 
 | |
| 	/* "neighbor local-as" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_local_as_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_local_as_no_prepend_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_local_as_cmd);
 | |
| 
 | |
| 	/* "neighbor solo" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_solo_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_solo_cmd);
 | |
| 
 | |
| 	/* "neighbor password" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_password_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_password_cmd);
 | |
| 
 | |
| 	/* "neighbor activate" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_activate_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_activate_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_activate_cmd);
 | |
| 
 | |
| 	/* "no neighbor activate" commands. */
 | |
| 	install_element(BGP_NODE, &no_neighbor_activate_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_activate_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_activate_cmd);
 | |
| 
 | |
| 	/* "neighbor peer-group" set commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_set_peer_group_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&neighbor_set_peer_group_hidden_cmd);
 | |
| 
 | |
| 	/* "no neighbor peer-group unset" commands. */
 | |
| 	install_element(BGP_NODE, &no_neighbor_set_peer_group_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&no_neighbor_set_peer_group_hidden_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&no_neighbor_set_peer_group_hidden_cmd);
 | |
| 
 | |
| 	/* "neighbor softreconfiguration inbound" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_soft_reconfiguration_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&no_neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_soft_reconfiguration_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_soft_reconfiguration_cmd);
 | |
| 
 | |
| 	/* "neighbor attribute-unchanged" commands.  */
 | |
| 	install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_attr_unchanged_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_attr_unchanged_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_attr_unchanged_cmd);
 | |
| 
 | |
| 	/* "nexthop-local unchanged" commands */
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_nexthop_local_unchanged_cmd);
 | |
| 
 | |
| 	/* "neighbor next-hop-self" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_nexthop_self_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_nexthop_self_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd);
 | |
| 
 | |
| 	/* "neighbor next-hop-self force" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_nexthop_self_force_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_nexthop_self_all_hidden_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd);
 | |
| 
 | |
| 	/* "neighbor as-override" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_as_override_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_as_override_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_as_override_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_as_override_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_as_override_cmd);
 | |
| 
 | |
| 	/* "neighbor remove-private-AS" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_remove_private_as_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_remove_private_as_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_remove_private_as_all_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_hidden_cmd);
 | |
| 	install_element(
 | |
| 		BGP_NODE,
 | |
| 		&no_neighbor_remove_private_as_all_replace_as_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_remove_private_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_remove_private_as_all_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_remove_private_as_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_remove_private_as_all_replace_as_cmd);
 | |
| 
 | |
| 	/* "neighbor send-community" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_send_community_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_send_community_type_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_send_community_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_send_community_type_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_send_community_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_send_community_type_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd);
 | |
| 
 | |
| 	/* "neighbor route-reflector" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_route_reflector_client_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&no_neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
 | |
| 
 | |
| 	/* "neighbor route-server" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE,
 | |
| 			&no_neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_server_client_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE,
 | |
| 			&no_neighbor_route_server_client_cmd);
 | |
| 
 | |
| 	/* "neighbor disable-addpath-rx" commands. */
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_disable_addpath_rx_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_disable_addpath_rx_cmd);
 | |
| 
 | |
| 	/* "neighbor addpath-tx-all-paths" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_addpath_tx_all_paths_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_addpath_tx_all_paths_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 | |
| 
 | |
| 	/* "neighbor addpath-tx-best-selected" commands.*/
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_addpath_tx_best_selected_paths_cmd);
 | |
| 
 | |
| 	/* "neighbor addpath-tx-bestpath-per-AS" commands.*/
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&no_neighbor_addpath_tx_bestpath_per_as_cmd);
 | |
| 
 | |
| 	/* "neighbor sender-as-path-loop-detection" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd);
 | |
| 
 | |
| 	/* "neighbor path-attribute discard" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_path_attribute_discard_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_path_attribute_discard_cmd);
 | |
| 
 | |
| 	/* "neighbor path-attribute treat-as-withdraw" commands. */
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_path_attribute_treat_as_withdraw_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_path_attribute_treat_as_withdraw_cmd);
 | |
| 
 | |
| 	/* "neighbor passive" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_passive_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_passive_cmd);
 | |
| 
 | |
| 
 | |
| 	/* "neighbor shutdown" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_shutdown_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_shutdown_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_shutdown_msg_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_shutdown_msg_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_shutdown_rtt_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_shutdown_rtt_cmd);
 | |
| 
 | |
| 	/* "neighbor capability extended-nexthop" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_capability_enhe_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_capability_enhe_cmd);
 | |
| 
 | |
| 	/* "neighbor capability software-version" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_capability_software_version_cmd);
 | |
| 
 | |
| 	/* "neighbor capability orf prefix-list" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_capability_orf_prefix_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_capability_orf_prefix_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd);
 | |
| 
 | |
| 	/* "neighbor capability dynamic" commands.*/
 | |
| 	install_element(BGP_NODE, &neighbor_capability_dynamic_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_capability_dynamic_cmd);
 | |
| 
 | |
| 	/* "neighbor dont-capability-negotiate" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_dont_capability_negotiate_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd);
 | |
| 
 | |
| 	/* "neighbor ebgp-multihop" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_ebgp_multihop_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_ebgp_multihop_cmd);
 | |
| 
 | |
| 	/* "neighbor disable-connected-check" commands.  */
 | |
| 	install_element(BGP_NODE, &neighbor_disable_connected_check_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_disable_connected_check_cmd);
 | |
| 
 | |
| 	/* "neighbor disable-link-bw-encoding-ieee" commands.  */
 | |
| 	install_element(BGP_NODE, &neighbor_disable_link_bw_encoding_ieee_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_disable_link_bw_encoding_ieee_cmd);
 | |
| 
 | |
| 	/* "neighbor extended-optional-parameters" commands.  */
 | |
| 	install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&no_neighbor_extended_optional_parameters_cmd);
 | |
| 
 | |
| 	/* "neighbor enforce-first-as" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_enforce_first_as_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_enforce_first_as_cmd);
 | |
| 
 | |
| 	/* "neighbor description" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_description_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_description_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_description_comment_cmd);
 | |
| 
 | |
| 	/* "neighbor update-source" commands. "*/
 | |
| 	install_element(BGP_NODE, &neighbor_update_source_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_update_source_cmd);
 | |
| 
 | |
| 	/* "neighbor default-originate" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_default_originate_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_default_originate_rmap_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_default_originate_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_default_originate_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_default_originate_rmap_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_default_originate_cmd);
 | |
| 
 | |
| 	/* "neighbor port" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_port_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_port_cmd);
 | |
| 
 | |
| 	/* "neighbor weight" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_weight_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_weight_hidden_cmd);
 | |
| 
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_weight_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_weight_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_weight_cmd);
 | |
| 
 | |
| 	/* "neighbor override-capability" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_override_capability_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_override_capability_cmd);
 | |
| 
 | |
| 	/* "neighbor strict-capability-match" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_strict_capability_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_strict_capability_cmd);
 | |
| 
 | |
| 	/* "neighbor timers" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_timers_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_timers_cmd);
 | |
| 
 | |
| 	/* "neighbor timers connect" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_timers_connect_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_timers_connect_cmd);
 | |
| 
 | |
| 	/* "neighbor timers delayopen" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_timers_delayopen_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_timers_delayopen_cmd);
 | |
| 
 | |
| 	/* "neighbor advertisement-interval" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_advertise_interval_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_advertise_interval_cmd);
 | |
| 
 | |
| 	/* "neighbor interface" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_interface_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_interface_cmd);
 | |
| 
 | |
| 	/* "neighbor distribute" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_distribute_list_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_distribute_list_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_distribute_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd);
 | |
| 
 | |
| 	/* "neighbor prefix-list" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_prefix_list_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_prefix_list_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd);
 | |
| 
 | |
| 	/* "neighbor filter-list" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_filter_list_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_filter_list_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_filter_list_cmd);
 | |
| 
 | |
| 	/* "neighbor route-map" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_route_map_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_route_map_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd);
 | |
| 
 | |
| 	/* "neighbor unsuppress-map" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_unsuppress_map_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd);
 | |
| 
 | |
| 	/* "neighbor advertise-map" commands. */
 | |
| 	install_element(BGP_NODE, &bgp_condadv_period_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_advertise_map_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_advertise_map_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_advertise_map_cmd);
 | |
| 
 | |
| 	/* bgp default-originate timer */
 | |
| 	install_element(BGP_NODE, &bgp_def_originate_eval_cmd);
 | |
| 
 | |
| 	/* neighbor maximum-prefix-out commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_out_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
 | |
| 
 | |
| 	/* "neighbor maximum-prefix" commands. */
 | |
| 	install_element(BGP_NODE, &neighbor_maximum_prefix_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_maximum_prefix_warning_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &neighbor_maximum_prefix_restart_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_maximum_prefix_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_warning_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_warning_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_restart_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE,
 | |
| 			&neighbor_maximum_prefix_threshold_restart_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd);
 | |
| 
 | |
| 	/* "neighbor allowas-in" */
 | |
| 	install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_allowas_in_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd);
 | |
| 
 | |
| 	/* neighbor accept-own */
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_accept_own_cmd);
 | |
| 
 | |
| 	/* "neighbor soo" */
 | |
| 	install_element(BGP_IPV4_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &no_neighbor_soo_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &neighbor_soo_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd);
 | |
| 
 | |
| 	/* address-family commands. */
 | |
| 	install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
 | |
| 	install_element(BGP_NODE, &address_family_ipv6_safi_cmd);
 | |
| #ifdef KEEP_OLD_VPN_COMMANDS
 | |
| 	install_element(BGP_NODE, &address_family_vpnv4_cmd);
 | |
| 	install_element(BGP_NODE, &address_family_vpnv6_cmd);
 | |
| #endif /* KEEP_OLD_VPN_COMMANDS */
 | |
| 
 | |
| 	install_element(BGP_NODE, &address_family_evpn_cmd);
 | |
| 
 | |
| 	/* "exit-address-family" command. */
 | |
| 	install_element(BGP_IPV4_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_IPV4M_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_IPV4L_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_IPV6M_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_IPV6L_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_VPNV4_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
 | |
| 	install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
 | |
| 
 | |
| 	/* BGP retain all route-target */
 | |
| 	install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd);
 | |
| 	install_element(BGP_VPNV6_NODE, &bgp_retain_route_target_cmd);
 | |
| 
 | |
| 	/* "clear ip bgp commands" */
 | |
| 	install_element(ENABLE_NODE, &clear_ip_bgp_all_cmd);
 | |
| 
 | |
| 	/* clear ip bgp prefix  */
 | |
| 	install_element(ENABLE_NODE, &clear_ip_bgp_prefix_cmd);
 | |
| 	install_element(ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd);
 | |
| 	install_element(ENABLE_NODE, &clear_bgp_instance_ipv6_safi_prefix_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp summary" commands. */
 | |
| 	install_element(VIEW_NODE, &show_bgp_instance_all_ipv6_updgrps_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_updgrps_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_instance_updgrps_stats_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_updgrps_stats_cmd);
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_instance_updgrps_adj_s_cmd);
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_summary_cmd);
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_updgrps_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp neighbors" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_neighbors_cmd);
 | |
| 
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_neighbors_graceful_restart_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp peer-group" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_peer_groups_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp paths" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_paths_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp community" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_community_info_cmd);
 | |
| 
 | |
| 	/* "show ip bgp large-community" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
 | |
| 	/* "show [ip] bgp attribute-info" commands. */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_attr_info_cmd);
 | |
| 	/* "show [ip] bgp route-leak" command */
 | |
| 	install_element(VIEW_NODE, &show_ip_bgp_route_leak_cmd);
 | |
| 
 | |
| 	/* "redistribute" commands.  */
 | |
| 	install_element(BGP_NODE, &bgp_redistribute_ipv4_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_redistribute_ipv4_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_redistribute_ipv4_rmap_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_redistribute_ipv4_metric_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_redistribute_ipv4_rmap_metric_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_redistribute_ipv4_metric_rmap_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_redistribute_ipv4_ospf_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_redistribute_ipv4_ospf_hidden_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_redistribute_ipv4_ospf_rmap_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_redistribute_ipv4_ospf_metric_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd);
 | |
| 	install_element(BGP_NODE,
 | |
| 			&bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_ospf_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_ospf_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_ospf_rmap_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_redistribute_ipv4_ospf_metric_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&bgp_redistribute_ipv4_ospf_rmap_metric_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&bgp_redistribute_ipv4_ospf_metric_rmap_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd);
 | |
| 
 | |
| 	/* import|export vpn [route-map RMAP_NAME] */
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_imexport_vpn_cmd);
 | |
| 
 | |
| 	install_element(BGP_IPV4_NODE, &bgp_imexport_vrf_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &bgp_imexport_vrf_cmd);
 | |
| 
 | |
| 	/* ttl_security commands */
 | |
| 	install_element(BGP_NODE, &neighbor_ttl_security_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
 | |
| 
 | |
| 	/* "bgp tcp-keepalive" commands */
 | |
| 	install_element(BGP_NODE, &bgp_tcp_keepalive_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_tcp_keepalive_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp memory" commands. */
 | |
| 	install_element(VIEW_NODE, &show_bgp_memory_cmd);
 | |
| 
 | |
| 	/* "show bgp martian next-hop" */
 | |
| 	install_element(VIEW_NODE, &show_bgp_martian_nexthop_db_cmd);
 | |
| 
 | |
| 	install_element(VIEW_NODE, &show_bgp_mac_hash_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp views" commands. */
 | |
| 	install_element(VIEW_NODE, &show_bgp_views_cmd);
 | |
| 
 | |
| 	/* "show [ip] bgp vrfs" commands. */
 | |
| 	install_element(VIEW_NODE, &show_bgp_vrfs_cmd);
 | |
| 
 | |
| 	/* Community-list. */
 | |
| 	community_list_vty();
 | |
| 
 | |
| 	community_alias_vty();
 | |
| 
 | |
| 	/* vpn-policy commands */
 | |
| 	install_element(BGP_IPV4_NODE, &af_rd_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_rd_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_label_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_label_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV4_NODE,
 | |
| 			&af_label_vpn_export_allocation_mode_cmd);
 | |
| 	install_element(BGP_IPV6_NODE,
 | |
| 			&af_label_vpn_export_allocation_mode_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_nexthop_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_nexthop_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_rt_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_rt_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_route_map_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_route_map_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_import_vrf_route_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_import_vrf_route_map_cmd);
 | |
| 
 | |
| 	install_element(BGP_IPV4_NODE, &af_routetarget_import_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_routetarget_import_cmd);
 | |
| 
 | |
| 	install_element(BGP_IPV4_NODE, &af_no_rd_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_no_rd_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_no_label_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_no_label_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_no_rt_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_no_rt_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_no_route_map_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_no_route_map_vpn_imexport_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_no_import_vrf_route_map_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_no_import_vrf_route_map_cmd);
 | |
| 
 | |
| 	/* tcp-mss command */
 | |
| 	install_element(BGP_NODE, &neighbor_tcp_mss_cmd);
 | |
| 	install_element(BGP_NODE, &no_neighbor_tcp_mss_cmd);
 | |
| 
 | |
| 	/* srv6 commands */
 | |
| 	install_element(VIEW_NODE, &show_bgp_srv6_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_segment_routing_srv6_cmd);
 | |
| 	install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
 | |
| 	install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
 | |
| 	install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
 | |
| 	install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
 | |
| 	install_element(BGP_NODE, &bgp_sid_vpn_export_cmd);
 | |
| 	install_element(BGP_NODE, &no_bgp_sid_vpn_export_cmd);
 | |
| 
 | |
| 	bgp_vty_if_init();
 | |
| }
 | |
| 
 | |
| #include "memory.h"
 | |
| #include "bgp_regex.h"
 | |
| #include "bgp_clist.h"
 | |
| #include "bgp_ecommunity.h"
 | |
| 
 | |
| /* VTY functions.  */
 | |
| 
 | |
| /* Direction value to string conversion.  */
 | |
| static const char *community_direct_str(int direct)
 | |
| {
 | |
| 	switch (direct) {
 | |
| 	case COMMUNITY_DENY:
 | |
| 		return "deny";
 | |
| 	case COMMUNITY_PERMIT:
 | |
| 		return "permit";
 | |
| 	default:
 | |
| 		return "unknown";
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Display error string.  */
 | |
| static void community_list_perror(struct vty *vty, int ret)
 | |
| {
 | |
| 	switch (ret) {
 | |
| 	case COMMUNITY_LIST_ERR_CANT_FIND_LIST:
 | |
| 		vty_out(vty, "%% Can't find community-list\n");
 | |
| 		break;
 | |
| 	case COMMUNITY_LIST_ERR_MALFORMED_VAL:
 | |
| 		vty_out(vty, "%% Malformed community-list value\n");
 | |
| 		break;
 | |
| 	case COMMUNITY_LIST_ERR_STANDARD_CONFLICT:
 | |
| 		vty_out(vty,
 | |
| 			"%% Community name conflict, previously defined as standard community\n");
 | |
| 		break;
 | |
| 	case COMMUNITY_LIST_ERR_EXPANDED_CONFLICT:
 | |
| 		vty_out(vty,
 | |
| 			"%% Community name conflict, previously defined as expanded community\n");
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* "community-list" keyword help string.  */
 | |
| #define COMMUNITY_LIST_STR "Add a community list entry\n"
 | |
| 
 | |
| /*community-list standard */
 | |
| DEFUN (community_list_standard,
 | |
|        bgp_community_list_standard_cmd,
 | |
|        "bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        BGP_STR
 | |
|        COMMUNITY_LIST_STR
 | |
|        "Community list number (standard)\n"
 | |
|        "Add an standard community-list entry\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        COMMUNITY_VAL_STR)
 | |
| {
 | |
| 	char *cl_name_or_number = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	int direct = 0;
 | |
| 	int style = COMMUNITY_LIST_STANDARD;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_name_or_number = argv[idx]->arg;
 | |
| 	direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
 | |
| 						       : COMMUNITY_DENY;
 | |
| 	argv_find(argv, argc, "AA:NN", &idx);
 | |
| 	char *str = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	assert(str);
 | |
| 	int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
 | |
| 				     direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		/* Display error string.  */
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_community_list_standard_all,
 | |
|        no_bgp_community_list_standard_all_cmd,
 | |
|        "no bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        COMMUNITY_LIST_STR
 | |
|        "Community list number (standard)\n"
 | |
|        "Add an standard community-list entry\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        COMMUNITY_VAL_STR)
 | |
| {
 | |
| 	char *cl_name_or_number = NULL;
 | |
| 	char *str = NULL;
 | |
| 	int direct = 0;
 | |
| 	int style = COMMUNITY_LIST_STANDARD;
 | |
| 	char *seq = NULL;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "permit", &idx);
 | |
| 	argv_find(argv, argc, "deny", &idx);
 | |
| 
 | |
| 	if (idx) {
 | |
| 		direct = argv_find(argv, argc, "permit", &idx)
 | |
| 				 ? COMMUNITY_PERMIT
 | |
| 				 : COMMUNITY_DENY;
 | |
| 
 | |
| 		idx = 0;
 | |
| 		argv_find(argv, argc, "AA:NN", &idx);
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_name_or_number = argv[idx]->arg;
 | |
| 
 | |
| 	int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
 | |
| 				       direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cmd,
 | |
|       "no bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME>",
 | |
|       NO_STR BGP_STR COMMUNITY_LIST_STR
 | |
|       "Community list number (standard)\n"
 | |
|       "Add an standard community-list entry\n"
 | |
|       "Community list name\n")
 | |
| 
 | |
| /*community-list expanded */
 | |
| DEFUN (community_list_expanded_all,
 | |
|        bgp_community_list_expanded_all_cmd,
 | |
|        "bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        BGP_STR
 | |
|        COMMUNITY_LIST_STR
 | |
|        "Community list number (expanded)\n"
 | |
|        "Add an expanded community-list entry\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        COMMUNITY_VAL_STR)
 | |
| {
 | |
| 	char *cl_name_or_number = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	int direct = 0;
 | |
| 	int style = COMMUNITY_LIST_EXPANDED;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_name_or_number = argv[idx]->arg;
 | |
| 	direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
 | |
| 						       : COMMUNITY_DENY;
 | |
| 	argv_find(argv, argc, "AA:NN", &idx);
 | |
| 	char *str = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	assert(str);
 | |
| 	int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
 | |
| 				     direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		/* Display error string.  */
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_community_list_expanded_all,
 | |
|        no_bgp_community_list_expanded_all_cmd,
 | |
|        "no bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        COMMUNITY_LIST_STR
 | |
|        "Community list number (expanded)\n"
 | |
|        "Add an expanded community-list entry\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        COMMUNITY_VAL_STR)
 | |
| {
 | |
| 	char *cl_name_or_number = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	char *str = NULL;
 | |
| 	int direct = 0;
 | |
| 	int style = COMMUNITY_LIST_EXPANDED;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "permit", &idx);
 | |
| 	argv_find(argv, argc, "deny", &idx);
 | |
| 
 | |
| 	if (idx) {
 | |
| 		direct = argv_find(argv, argc, "permit", &idx)
 | |
| 				 ? COMMUNITY_PERMIT
 | |
| 				 : COMMUNITY_DENY;
 | |
| 
 | |
| 		idx = 0;
 | |
| 		argv_find(argv, argc, "AA:NN", &idx);
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_name_or_number = argv[idx]->arg;
 | |
| 
 | |
| 	int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
 | |
| 				       direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_community_list_expanded_all,
 | |
|       no_bgp_community_list_expanded_all_list_cmd,
 | |
|       "no bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME>",
 | |
|       NO_STR BGP_STR COMMUNITY_LIST_STR
 | |
|       "Community list number (expanded)\n"
 | |
|       "Add an expanded community-list entry\n"
 | |
|       "Community list name\n")
 | |
| 
 | |
| /* Return configuration string of community-list entry.  */
 | |
| static const char *community_list_config_str(struct community_entry *entry)
 | |
| {
 | |
| 	const char *str;
 | |
| 
 | |
| 	if (entry->style == COMMUNITY_LIST_STANDARD)
 | |
| 		str = community_str(entry->u.com, false, false);
 | |
| 	else if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
 | |
| 		str = lcommunity_str(entry->u.lcom, false, false);
 | |
| 	else
 | |
| 		str = entry->config;
 | |
| 
 | |
| 	return str;
 | |
| }
 | |
| 
 | |
| static void community_list_show(struct vty *vty, struct community_list *list)
 | |
| {
 | |
| 	struct community_entry *entry;
 | |
| 
 | |
| 	for (entry = list->head; entry; entry = entry->next) {
 | |
| 		if (entry == list->head) {
 | |
| 			if (all_digit(list->name))
 | |
| 				vty_out(vty, "Community %s list %s\n",
 | |
| 					entry->style == COMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "(expanded) access",
 | |
| 					list->name);
 | |
| 			else
 | |
| 				vty_out(vty, "Named Community %s list %s\n",
 | |
| 					entry->style == COMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "expanded",
 | |
| 					list->name);
 | |
| 		}
 | |
| 		vty_out(vty, "    %s %s\n", community_direct_str(entry->direct),
 | |
| 			community_list_config_str(entry));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFUN (show_community_list,
 | |
|        show_bgp_community_list_cmd,
 | |
|        "show bgp community-list",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List community-list\n")
 | |
| {
 | |
| 	struct community_list *list;
 | |
| 	struct community_list_master *cm;
 | |
| 
 | |
| 	cm = community_list_master_lookup(bgp_clist, COMMUNITY_LIST_MASTER);
 | |
| 	if (!cm)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		community_list_show(vty, list);
 | |
| 
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		community_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_community_list_arg,
 | |
|        show_bgp_community_list_arg_cmd,
 | |
|        "show bgp community-list <(1-500)|COMMUNITY_LIST_NAME> detail",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List community-list\n"
 | |
|        "Community-list number\n"
 | |
|        "Community-list name\n"
 | |
|        "Detailed information on community-list\n")
 | |
| {
 | |
| 	int idx_comm_list = 3;
 | |
| 	struct community_list *list;
 | |
| 
 | |
| 	list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
 | |
| 				     COMMUNITY_LIST_MASTER);
 | |
| 	if (!list) {
 | |
| 		vty_out(vty, "%% Can't find community-list\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	community_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Large Community code.
 | |
|  */
 | |
| static int lcommunity_list_set_vty(struct vty *vty, int argc,
 | |
| 				   struct cmd_token **argv, int style,
 | |
| 				   int reject_all_digit_name)
 | |
| {
 | |
| 	int ret;
 | |
| 	int direct;
 | |
| 	char *str;
 | |
| 	int idx = 0;
 | |
| 	char *cl_name;
 | |
| 	char *seq = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
 | |
| 						       : COMMUNITY_DENY;
 | |
| 
 | |
| 	/* All digit name check.  */
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx);
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	cl_name = argv[idx]->arg;
 | |
| 	if (reject_all_digit_name && all_digit(cl_name)) {
 | |
| 		vty_out(vty, "%% Community name cannot have all digits\n");
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "AA:BB:CC", &idx);
 | |
| 	argv_find(argv, argc, "LINE", &idx);
 | |
| 	/* Concat community string argument. */
 | |
| 	if (idx)
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	else
 | |
| 		str = NULL;
 | |
| 
 | |
| 	ret = lcommunity_list_set(bgp_clist, cl_name, str, seq, direct, style);
 | |
| 
 | |
| 	/* Free temporary community list string allocated by
 | |
| 	   argv_concat().  */
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int lcommunity_list_unset_vty(struct vty *vty, int argc,
 | |
| 				     struct cmd_token **argv, int style)
 | |
| {
 | |
| 	int ret;
 | |
| 	int direct = 0;
 | |
| 	char *str = NULL;
 | |
| 	int idx = 0;
 | |
| 	char *seq = NULL;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "permit", &idx);
 | |
| 	argv_find(argv, argc, "deny", &idx);
 | |
| 
 | |
| 	if (idx) {
 | |
| 		/* Check the list direct. */
 | |
| 		if (strncmp(argv[idx]->arg, "p", 1) == 0)
 | |
| 			direct = COMMUNITY_PERMIT;
 | |
| 		else
 | |
| 			direct = COMMUNITY_DENY;
 | |
| 
 | |
| 		idx = 0;
 | |
| 		argv_find(argv, argc, "LINE", &idx);
 | |
| 		argv_find(argv, argc, "AA:AA:NN", &idx);
 | |
| 		/* Concat community string argument.  */
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx);
 | |
| 
 | |
| 	/* Unset community list.  */
 | |
| 	ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
 | |
| 				    style);
 | |
| 
 | |
| 	/* Free temporary community list string allocated by
 | |
| 	   argv_concat().  */
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "large-community-list" keyword help string.  */
 | |
| #define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
 | |
| #define LCOMMUNITY_VAL_STR  "large community in 'aa:bb:cc' format\n"
 | |
| 
 | |
| DEFUN (lcommunity_list_standard,
 | |
|        bgp_lcommunity_list_standard_cmd,
 | |
|        "bgp large-community-list (1-99) [seq (0-4294967295)] <deny|permit> AA:BB:CC...",
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Large Community list number (standard)\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        LCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	return lcommunity_list_set_vty(vty, argc, argv,
 | |
| 				       LARGE_COMMUNITY_LIST_STANDARD, 0);
 | |
| }
 | |
| 
 | |
| DEFUN (lcommunity_list_expanded,
 | |
|        bgp_lcommunity_list_expanded_cmd,
 | |
|        "bgp large-community-list (100-500) [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Large Community list number (expanded)\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	return lcommunity_list_set_vty(vty, argc, argv,
 | |
| 				       LARGE_COMMUNITY_LIST_EXPANDED, 0);
 | |
| }
 | |
| 
 | |
| DEFUN (lcommunity_list_name_standard,
 | |
|        bgp_lcommunity_list_name_standard_cmd,
 | |
|        "bgp large-community-list standard LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> AA:BB:CC...",
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify standard large-community-list\n"
 | |
|        "Large Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        LCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	return lcommunity_list_set_vty(vty, argc, argv,
 | |
| 				       LARGE_COMMUNITY_LIST_STANDARD, 1);
 | |
| }
 | |
| 
 | |
| DEFUN (lcommunity_list_name_expanded,
 | |
|        bgp_lcommunity_list_name_expanded_cmd,
 | |
|        "bgp large-community-list expanded LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify expanded large-community-list\n"
 | |
|        "Large Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	return lcommunity_list_set_vty(vty, argc, argv,
 | |
| 				       LARGE_COMMUNITY_LIST_EXPANDED, 1);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_all,
 | |
|        no_bgp_lcommunity_list_all_cmd,
 | |
|        "no bgp large-community-list <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME>",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Large Community list number (standard)\n"
 | |
|        "Large Community list number (expanded)\n"
 | |
|        "Large Community list name\n")
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_STANDARD);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_name_standard_all,
 | |
|        no_bgp_lcommunity_list_name_standard_all_cmd,
 | |
|        "no bgp large-community-list standard LCOMMUNITY_LIST_NAME",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify standard large-community-list\n"
 | |
|        "Large Community list name\n")
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_STANDARD);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_name_expanded_all,
 | |
|        no_bgp_lcommunity_list_name_expanded_all_cmd,
 | |
|        "no bgp large-community-list expanded LCOMMUNITY_LIST_NAME",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify expanded large-community-list\n"
 | |
|        "Large Community list name\n")
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_EXPANDED);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_standard,
 | |
|        no_bgp_lcommunity_list_standard_cmd,
 | |
|        "no bgp large-community-list (1-99) [seq (0-4294967295)] <deny|permit> AA:AA:NN...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Large Community list number (standard)\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        LCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_STANDARD);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_expanded,
 | |
|        no_bgp_lcommunity_list_expanded_cmd,
 | |
|        "no bgp large-community-list (100-500) [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Large Community list number (expanded)\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_EXPANDED);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_name_standard,
 | |
|        no_bgp_lcommunity_list_name_standard_cmd,
 | |
|        "no bgp large-community-list standard LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> AA:AA:NN...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify standard large-community-list\n"
 | |
|        "Large Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        LCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_STANDARD);
 | |
| }
 | |
| 
 | |
| DEFUN (no_lcommunity_list_name_expanded,
 | |
|        no_bgp_lcommunity_list_name_expanded_cmd,
 | |
|        "no bgp large-community-list expanded LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        LCOMMUNITY_LIST_STR
 | |
|        "Specify expanded large-community-list\n"
 | |
|        "Large community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify large community to reject\n"
 | |
|        "Specify large community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	return lcommunity_list_unset_vty(vty, argc, argv,
 | |
| 					 LARGE_COMMUNITY_LIST_EXPANDED);
 | |
| }
 | |
| 
 | |
| static void lcommunity_list_show(struct vty *vty, struct community_list *list)
 | |
| {
 | |
| 	struct community_entry *entry;
 | |
| 
 | |
| 	for (entry = list->head; entry; entry = entry->next) {
 | |
| 		if (entry == list->head) {
 | |
| 			if (all_digit(list->name))
 | |
| 				vty_out(vty, "Large community %s list %s\n",
 | |
| 					entry->style ==
 | |
| 						LARGE_COMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "(expanded) access",
 | |
| 					list->name);
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"Named large community %s list %s\n",
 | |
| 					entry->style ==
 | |
| 						LARGE_COMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "expanded",
 | |
| 					list->name);
 | |
| 		}
 | |
| 		vty_out(vty, "    %s %s\n", community_direct_str(entry->direct),
 | |
| 			community_list_config_str(entry));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFUN (show_lcommunity_list,
 | |
|        show_bgp_lcommunity_list_cmd,
 | |
|        "show bgp large-community-list",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List large-community list\n")
 | |
| {
 | |
| 	struct community_list *list;
 | |
| 	struct community_list_master *cm;
 | |
| 
 | |
| 	cm = community_list_master_lookup(bgp_clist,
 | |
| 					  LARGE_COMMUNITY_LIST_MASTER);
 | |
| 	if (!cm)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		lcommunity_list_show(vty, list);
 | |
| 
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		lcommunity_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_lcommunity_list_arg,
 | |
|        show_bgp_lcommunity_list_arg_cmd,
 | |
|        "show bgp large-community-list <(1-500)|LCOMMUNITY_LIST_NAME> detail",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List large-community list\n"
 | |
|        "Large-community-list number\n"
 | |
|        "Large-community-list name\n"
 | |
|        "Detailed information on large-community-list\n")
 | |
| {
 | |
| 	struct community_list *list;
 | |
| 
 | |
| 	list = community_list_lookup(bgp_clist, argv[3]->arg, 0,
 | |
| 				     LARGE_COMMUNITY_LIST_MASTER);
 | |
| 	if (!list) {
 | |
| 		vty_out(vty, "%% Can't find large-community-list\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	lcommunity_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* "extcommunity-list" keyword help string.  */
 | |
| #define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
 | |
| #define EXTCOMMUNITY_VAL_STR  "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
 | |
| 
 | |
| DEFUN (extcommunity_list_standard,
 | |
|        bgp_extcommunity_list_standard_cmd,
 | |
|        "bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        BGP_STR
 | |
|        EXTCOMMUNITY_LIST_STR
 | |
|        "Extended Community list number (standard)\n"
 | |
|        "Specify standard extcommunity-list\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        EXTCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	int style = EXTCOMMUNITY_LIST_STANDARD;
 | |
| 	int direct = 0;
 | |
| 	char *cl_number_or_name = NULL;
 | |
| 	char *seq = NULL;
 | |
| 
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_number_or_name = argv[idx]->arg;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
 | |
| 						       : COMMUNITY_DENY;
 | |
| 	argv_find(argv, argc, "AA:NN", &idx);
 | |
| 	char *str = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
 | |
| 					direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (extcommunity_list_name_expanded,
 | |
|        bgp_extcommunity_list_name_expanded_cmd,
 | |
|        "bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        BGP_STR
 | |
|        EXTCOMMUNITY_LIST_STR
 | |
|        "Extended Community list number (expanded)\n"
 | |
|        "Specify expanded extcommunity-list\n"
 | |
|        "Extended Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	int style = EXTCOMMUNITY_LIST_EXPANDED;
 | |
| 	int direct = 0;
 | |
| 	char *cl_number_or_name = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_number_or_name = argv[idx]->arg;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
 | |
| 						       : COMMUNITY_DENY;
 | |
| 	argv_find(argv, argc, "LINE", &idx);
 | |
| 	char *str = argv_concat(argv, argc, idx);
 | |
| 
 | |
| 	int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
 | |
| 					direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_extcommunity_list_standard_all,
 | |
|        no_bgp_extcommunity_list_standard_all_cmd,
 | |
|        "no bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        EXTCOMMUNITY_LIST_STR
 | |
|        "Extended Community list number (standard)\n"
 | |
|        "Specify standard extcommunity-list\n"
 | |
|        "Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        EXTCOMMUNITY_VAL_STR)
 | |
| {
 | |
| 	int style = EXTCOMMUNITY_LIST_STANDARD;
 | |
| 	int direct = 0;
 | |
| 	char *cl_number_or_name = NULL;
 | |
| 	char *str = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "permit", &idx);
 | |
| 	argv_find(argv, argc, "deny", &idx);
 | |
| 	if (idx) {
 | |
| 		direct = argv_find(argv, argc, "permit", &idx)
 | |
| 				 ? COMMUNITY_PERMIT
 | |
| 				 : COMMUNITY_DENY;
 | |
| 
 | |
| 		idx = 0;
 | |
| 		argv_find(argv, argc, "AA:NN", &idx);
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(1-99)", &idx);
 | |
| 	argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_number_or_name = argv[idx]->arg;
 | |
| 
 | |
| 	int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
 | |
| 					  seq, direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_extcommunity_list_standard_all,
 | |
|       no_bgp_extcommunity_list_standard_all_list_cmd,
 | |
|       "no bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME>",
 | |
|       NO_STR BGP_STR EXTCOMMUNITY_LIST_STR
 | |
|       "Extended Community list number (standard)\n"
 | |
|       "Specify standard extcommunity-list\n"
 | |
|       "Community list name\n")
 | |
| 
 | |
| DEFUN (no_extcommunity_list_expanded_all,
 | |
|        no_bgp_extcommunity_list_expanded_all_cmd,
 | |
|        "no bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> LINE...",
 | |
|        NO_STR
 | |
|        BGP_STR
 | |
|        EXTCOMMUNITY_LIST_STR
 | |
|        "Extended Community list number (expanded)\n"
 | |
|        "Specify expanded extcommunity-list\n"
 | |
|        "Extended Community list name\n"
 | |
|        "Sequence number of an entry\n"
 | |
|        "Sequence number\n"
 | |
|        "Specify community to reject\n"
 | |
|        "Specify community to accept\n"
 | |
|        "An ordered list as a regular-expression\n")
 | |
| {
 | |
| 	int style = EXTCOMMUNITY_LIST_EXPANDED;
 | |
| 	int direct = 0;
 | |
| 	char *cl_number_or_name = NULL;
 | |
| 	char *str = NULL;
 | |
| 	char *seq = NULL;
 | |
| 	int idx = 0;
 | |
| 
 | |
| 	if (argv_find(argv, argc, "(0-4294967295)", &idx))
 | |
| 		seq = argv[idx]->arg;
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "permit", &idx);
 | |
| 	argv_find(argv, argc, "deny", &idx);
 | |
| 
 | |
| 	if (idx) {
 | |
| 		direct = argv_find(argv, argc, "permit", &idx)
 | |
| 				 ? COMMUNITY_PERMIT
 | |
| 				 : COMMUNITY_DENY;
 | |
| 
 | |
| 		idx = 0;
 | |
| 		argv_find(argv, argc, "LINE", &idx);
 | |
| 		str = argv_concat(argv, argc, idx);
 | |
| 	}
 | |
| 
 | |
| 	idx = 0;
 | |
| 	argv_find(argv, argc, "(100-500)", &idx);
 | |
| 	argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
 | |
| 	cl_number_or_name = argv[idx]->arg;
 | |
| 
 | |
| 	int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
 | |
| 					  seq, direct, style);
 | |
| 
 | |
| 	XFREE(MTYPE_TMP, str);
 | |
| 
 | |
| 	if (ret < 0) {
 | |
| 		community_list_perror(vty, ret);
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 	}
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| ALIAS(no_extcommunity_list_expanded_all,
 | |
|       no_bgp_extcommunity_list_expanded_all_list_cmd,
 | |
|       "no bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME>",
 | |
|       NO_STR BGP_STR EXTCOMMUNITY_LIST_STR
 | |
|       "Extended Community list number (expanded)\n"
 | |
|       "Specify expanded extcommunity-list\n"
 | |
|       "Extended Community list name\n")
 | |
| 
 | |
| static void extcommunity_list_show(struct vty *vty, struct community_list *list)
 | |
| {
 | |
| 	struct community_entry *entry;
 | |
| 
 | |
| 	for (entry = list->head; entry; entry = entry->next) {
 | |
| 		if (entry == list->head) {
 | |
| 			if (all_digit(list->name))
 | |
| 				vty_out(vty, "Extended community %s list %s\n",
 | |
| 					entry->style == EXTCOMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "(expanded) access",
 | |
| 					list->name);
 | |
| 			else
 | |
| 				vty_out(vty,
 | |
| 					"Named extended community %s list %s\n",
 | |
| 					entry->style == EXTCOMMUNITY_LIST_STANDARD
 | |
| 						? "standard"
 | |
| 						: "expanded",
 | |
| 					list->name);
 | |
| 		}
 | |
| 		vty_out(vty, "    %s %s\n", community_direct_str(entry->direct),
 | |
| 			community_list_config_str(entry));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| DEFUN (show_extcommunity_list,
 | |
|        show_bgp_extcommunity_list_cmd,
 | |
|        "show bgp extcommunity-list",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List extended-community list\n")
 | |
| {
 | |
| 	struct community_list *list;
 | |
| 	struct community_list_master *cm;
 | |
| 
 | |
| 	cm = community_list_master_lookup(bgp_clist, EXTCOMMUNITY_LIST_MASTER);
 | |
| 	if (!cm)
 | |
| 		return CMD_SUCCESS;
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		extcommunity_list_show(vty, list);
 | |
| 
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		extcommunity_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (show_extcommunity_list_arg,
 | |
|        show_bgp_extcommunity_list_arg_cmd,
 | |
|        "show bgp extcommunity-list <(1-500)|EXTCOMMUNITY_LIST_NAME> detail",
 | |
|        SHOW_STR
 | |
|        BGP_STR
 | |
|        "List extended-community list\n"
 | |
|        "Extcommunity-list number\n"
 | |
|        "Extcommunity-list name\n"
 | |
|        "Detailed information on extcommunity-list\n")
 | |
| {
 | |
| 	int idx_comm_list = 3;
 | |
| 	struct community_list *list;
 | |
| 
 | |
| 	list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
 | |
| 				     EXTCOMMUNITY_LIST_MASTER);
 | |
| 	if (!list) {
 | |
| 		vty_out(vty, "%% Can't find extcommunity-list\n");
 | |
| 		return CMD_WARNING;
 | |
| 	}
 | |
| 
 | |
| 	extcommunity_list_show(vty, list);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* Display community-list and extcommunity-list configuration.  */
 | |
| static int community_list_config_write(struct vty *vty)
 | |
| {
 | |
| 	struct community_list *list;
 | |
| 	struct community_entry *entry;
 | |
| 	struct community_list_master *cm;
 | |
| 	int write = 0;
 | |
| 
 | |
| 	/* Community-list.  */
 | |
| 	cm = community_list_master_lookup(bgp_clist, COMMUNITY_LIST_MASTER);
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp community-list %s seq %" PRId64 " %s %s\n",
 | |
| 				list->name, entry->seq,
 | |
| 				community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp community-list %s %s seq %" PRId64 " %s %s\n",
 | |
| 				entry->style == COMMUNITY_LIST_STANDARD
 | |
| 					? "standard"
 | |
| 					: "expanded",
 | |
| 				list->name, entry->seq,
 | |
| 				community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 
 | |
| 	/* Extcommunity-list.  */
 | |
| 	cm = community_list_master_lookup(bgp_clist, EXTCOMMUNITY_LIST_MASTER);
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp extcommunity-list %s seq %" PRId64 " %s %s\n",
 | |
| 				list->name, entry->seq,
 | |
| 				community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp extcommunity-list %s %s seq %" PRId64" %s %s\n",
 | |
| 				entry->style == EXTCOMMUNITY_LIST_STANDARD
 | |
| 					? "standard"
 | |
| 					: "expanded",
 | |
| 				list->name, entry->seq,
 | |
| 				community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 	/* lcommunity-list.  */
 | |
| 	cm = community_list_master_lookup(bgp_clist,
 | |
| 					  LARGE_COMMUNITY_LIST_MASTER);
 | |
| 
 | |
| 	for (list = cm->num.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp large-community-list %s seq %" PRId64" %s %s\n",
 | |
| 				list->name, entry->seq,
 | |
| 				community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 	for (list = cm->str.head; list; list = list->next)
 | |
| 		for (entry = list->head; entry; entry = entry->next) {
 | |
| 			vty_out(vty,
 | |
| 				"bgp large-community-list %s %s seq %" PRId64" %s %s\n",
 | |
| 
 | |
| 				entry->style == LARGE_COMMUNITY_LIST_STANDARD
 | |
| 					? "standard"
 | |
| 					: "expanded",
 | |
| 				list->name, entry->seq, community_direct_str(entry->direct),
 | |
| 				community_list_config_str(entry));
 | |
| 			write++;
 | |
| 		}
 | |
| 
 | |
| 	return write;
 | |
| }
 | |
| 
 | |
| static int community_list_config_write(struct vty *vty);
 | |
| static struct cmd_node community_list_node = {
 | |
| 	.name = "community list",
 | |
| 	.node = COMMUNITY_LIST_NODE,
 | |
| 	.prompt = "",
 | |
| 	.config_write = community_list_config_write,
 | |
| };
 | |
| 
 | |
| static void community_list_vty(void)
 | |
| {
 | |
| 	install_node(&community_list_node);
 | |
| 
 | |
| 	/* Community-list.  */
 | |
| 	install_element(CONFIG_NODE, &bgp_community_list_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_community_list_expanded_all_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_community_list_standard_all_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_community_list_standard_all_list_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_community_list_expanded_all_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_community_list_expanded_all_list_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_community_list_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_community_list_arg_cmd);
 | |
| 
 | |
| 	/* Extcommunity-list.  */
 | |
| 	install_element(CONFIG_NODE, &bgp_extcommunity_list_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_extcommunity_list_name_expanded_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_extcommunity_list_standard_all_cmd);
 | |
| 	install_element(CONFIG_NODE,
 | |
| 			&no_bgp_extcommunity_list_standard_all_list_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_extcommunity_list_expanded_all_cmd);
 | |
| 	install_element(CONFIG_NODE,
 | |
| 			&no_bgp_extcommunity_list_expanded_all_list_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_extcommunity_list_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_extcommunity_list_arg_cmd);
 | |
| 
 | |
| 	/* Large Community List */
 | |
| 	install_element(CONFIG_NODE, &bgp_lcommunity_list_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_lcommunity_list_all_cmd);
 | |
| 	install_element(CONFIG_NODE,
 | |
| 			&no_bgp_lcommunity_list_name_standard_all_cmd);
 | |
| 	install_element(CONFIG_NODE,
 | |
| 			&no_bgp_lcommunity_list_name_expanded_all_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_lcommunity_list_expanded_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_lcommunity_list_name_standard_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_bgp_lcommunity_list_name_expanded_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd);
 | |
| 	install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd);
 | |
| 
 | |
| 	bgp_community_list_command_completion_setup();
 | |
| }
 | |
| 
 | |
| static struct cmd_node community_alias_node = {
 | |
| 	.name = "community alias",
 | |
| 	.node = COMMUNITY_ALIAS_NODE,
 | |
| 	.prompt = "",
 | |
| 	.config_write = bgp_community_alias_write,
 | |
| };
 | |
| 
 | |
| void community_alias_vty(void)
 | |
| {
 | |
| 	install_node(&community_alias_node);
 | |
| 
 | |
| 	/* Community-list.  */
 | |
| 	install_element(CONFIG_NODE, &bgp_community_alias_cmd);
 | |
| 
 | |
| 	bgp_community_alias_command_completion_setup();
 | |
| }
 |