Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
15590 lines (13759 sloc) 466 KB
/* BGP VTY interface.
* Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "command.h"
#include "lib/json.h"
#include "lib/zclient.h"
#include "prefix.h"
#include "plist.h"
#include "buffer.h"
#include "linklist.h"
#include "stream.h"
#include "thread.h"
#include "log.h"
#include "memory.h"
#include "memory_vty.h"
#include "hash.h"
#include "queue.h"
#include "filter.h"
#include "frrstr.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_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_nexthop.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_addpath.h"
#include "bgpd/bgp_mac.h"
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
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;
break;
case SAFI_MULTICAST:
return BGP_IPV4M_NODE;
break;
case SAFI_LABELED_UNICAST:
return BGP_IPV4L_NODE;
break;
case SAFI_MPLS_VPN:
return BGP_VPNV4_NODE;
break;
case SAFI_FLOWSPEC:
return BGP_FLOWSPECV4_NODE;
default:
/* not expected */
return BGP_IPV4_NODE;
break;
}
break;
case AFI_IP6:
switch (safi) {
case SAFI_UNICAST:
return BGP_IPV6_NODE;
break;
case SAFI_MULTICAST:
return BGP_IPV6M_NODE;
break;
case SAFI_LABELED_UNICAST:
return BGP_IPV6L_NODE;
break;
case SAFI_MPLS_VPN:
return BGP_VPNV6_NODE;
break;
case SAFI_FLOWSPEC:
return BGP_FLOWSPECV6_NODE;
default:
/* not expected */
return BGP_IPV4_NODE;
break;
}
break;
case AFI_L2VPN:
return BGP_EVPN_NODE;
break;
case AFI_MAX:
// We should never be here but to clarify the switch statement..
return BGP_IPV4_NODE;
break;
}
// Impossible to happen
return BGP_IPV4_NODE;
}
/* 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;
}
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, "flowspec", index)) {
ret = 1;
if (safi)
*safi = SAFI_FLOWSPEC;
}
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.
*
* 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)
vty_out(vty, "{}\n");
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)
vty_out(vty, "{}\n");
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 int peer_address_self_check(struct bgp *bgp, union sockunion *su)
{
struct interface *ifp = NULL;
if (su->sa.sa_family == AF_INET)
ifp = if_lookup_by_ipv4_exact(&su->sin.sin_addr, bgp->vrf_id);
else if (su->sa.sa_family == AF_INET6)
ifp = if_lookup_by_ipv6_exact(&su->sin6.sin6_addr,
su->sin6.sin6_scope_id,
bgp->vrf_id);
if (ifp)
return 1;
return 0;
}
/* 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)) {
vty_out(vty,
"%% Operation not allowed on a dynamic neighbor\n");
return NULL;
}
return peer;
}
if (group)
return group->conf;
vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
return NULL;
}
int bgp_vty_return(struct vty *vty, int ret)
{
const char *str = NULL;
switch (ret) {
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_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP:
str = "Local-AS allowed only for EBGP 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;
}
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:
vty_out(vty,
"%%BGP: Enable %s address family for the neighbor %s\n",
afi_safi_print(afi, safi), peer->host);
break;
case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
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);
break;
default:
break;
}
}
/* `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;
bool found = false;
struct peer *peer;
struct listnode *node, *nnode;
/* 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)) {
if (!peer->afc[afi][safi])
continue;
if (stype == BGP_CLEAR_SOFT_NONE)
ret = peer_clear(peer, &nnode);
else
ret = peer_clear_soft(peer, afi, safi, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
else
found = true;
}
/* This is to apply read-only mode on this clear. */
if (stype == BGP_CLEAR_SOFT_NONE)
bgp->update_delay_over = 0;
if (!found)
vty_out(vty, "%%BGP: No %s peer configured\n",
afi_safi_print(afi, safi));
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;
}
}
if (!peer->afc[afi][safi])
ret = BGP_ERR_AF_UNCONFIGURED;
else if (stype == BGP_CLEAR_SOFT_NONE)
ret = peer_clear(peer, NULL);
else
ret = peer_clear_soft(peer, afi, safi, stype);
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)) {
if (!peer->afc[afi][safi])
continue;
if (stype == BGP_CLEAR_SOFT_NONE)
ret = peer_clear(peer, NULL);
else
ret = peer_clear_soft(peer, afi, safi, 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",
afi_safi_print(afi, safi), 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;
if (!peer->afc[afi][safi])
continue;
if (stype == BGP_CLEAR_SOFT_NONE)
ret = peer_clear(peer, &nnode);
else
ret = peer_clear_soft(peer, afi, safi, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
else
found = true;
}
if (!found)
vty_out(vty,
"%%BGP: No external %s peer is configured\n",
afi_safi_print(afi, safi));
return CMD_SUCCESS;
}
/* Clear all neighbors belonging to a specific AS. */
if (sort == clear_as) {
as_t as = strtoul(arg, NULL, 10);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as != as)
continue;
if (!peer->afc[afi][safi])
ret = BGP_ERR_AF_UNCONFIGURED;
else if (stype == BGP_CLEAR_SOFT_NONE)
ret = peer_clear(peer, &nnode);
else
ret = peer_clear_soft(peer, afi, safi, 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 is configured with AS %s\n",
afi_safi_print(afi, safi), 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)
{
bgp_clear_vty(vty, name, AFI_IP, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_IN, NULL);
bgp_clear_vty(vty, name, AFI_IP6, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_IN, NULL);
}
/* clear soft outbound */
static void bgp_clear_star_soft_out(struct vty *vty, const char *name)
{
bgp_clear_vty(vty, name, AFI_IP, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_OUT, NULL);
bgp_clear_vty(vty, name, AFI_IP6, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_OUT, NULL);
}
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_vty_clippy.c"
#endif
/* BGP global configuration. */
#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated bgp multiple-instance")
CPP_NOTICE("This includes BGP_OPT_MULTIPLE_INSTANCE")
#endif
DEFUN_HIDDEN (bgp_multiple_instance_func,
bgp_multiple_instance_cmd,
"bgp multiple-instance",
BGP_STR
"Enable bgp multiple instance\n")
{
bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (no_bgp_multiple_instance,
no_bgp_multiple_instance_cmd,
"no bgp multiple-instance",
NO_STR
BGP_STR
"BGP multiple instance\n")
{
int ret;
vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
vty_out(vty, "if you are using this please let the developers know\n");
zlog_info("Deprecated option: `bgp multiple-instance` being used");
ret = bgp_option_unset(BGP_OPT_MULTIPLE_INSTANCE);
if (ret < 0) {
vty_out(vty, "%% There are more than two BGP instances\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
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);
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;
}
#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco")
CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG")
#endif
DEFUN_HIDDEN (bgp_config_type,
bgp_config_type_cmd,
"bgp config-type <cisco|zebra>",
BGP_STR
"Configuration type\n"
"cisco\n"
"zebra\n")
{
int idx = 0;
if (argv_find(argv, argc, "cisco", &idx)) {
vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
vty_out(vty, "if you are using this please let the developers know!\n");
zlog_info("Deprecated option: `bgp config-type cisco` being used");
bgp_option_set(BGP_OPT_CONFIG_CISCO);
} else
bgp_option_unset(BGP_OPT_CONFIG_CISCO);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (no_bgp_config_type,
no_bgp_config_type_cmd,
"no bgp config-type [<cisco|zebra>]",
NO_STR
BGP_STR
"Display configuration type\n"
"cisco\n"
"zebra\n")
{
bgp_option_unset(BGP_OPT_CONFIG_CISCO);
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 [(1-4294967295) [<view|vrf> VIEWVRFNAME]]",
ROUTER_STR
BGP_STR
AS_STR
BGP_INSTANCE_HELP_STR)
{
int idx_asn = 2;
int idx_view_vrf = 3;
int idx_vrf = 4;
int is_new_bgp = 0;
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 {
as = strtoul(argv[idx_asn]->arg, NULL, 10);
inst_type = BGP_INSTANCE_TYPE_DEFAULT;
if (argc > 3) {
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 (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
is_new_bgp = (bgp_lookup(as, name) == NULL);
ret = bgp_get(&bgp, &as, name, inst_type);
switch (ret) {
case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
vty_out(vty,
"Please specify 'bgp multiple-instance' first\n");
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_AS_MISMATCH:
vty_out(vty, "BGP is already running; AS is %u\n", as);
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 %u\n",
as);
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();
/* Pending: handle when user tries to change a view to vrf n vv.
*/
}
/* 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 [(1-4294967295) [<view|vrf> VIEWVRFNAME]]",
NO_STR
ROUTER_STR
BGP_STR
AS_STR
BGP_INSTANCE_HELP_STR)
{
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",
bgp->l3vni);
return CMD_WARNING_CONFIG_FAILED;
}
} else {
as = strtoul(argv[idx_asn]->arg, NULL, 10);
if (argc > 4)
name = argv[idx_vrf]->arg;
/* 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",
bgp->l3vni);
return CMD_WARNING_CONFIG_FAILED;
}
}
bgp_delete(bgp);
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;
}
/* 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;
}
DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd,
"bgp confederation identifier (1-4294967295)",
"BGP specific commands\n"
"AS confederation parameters\n"
"AS number\n"
"Set routing domain confederation AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
as_t as;
as = strtoul(argv[idx_number]->arg, NULL, 10);
bgp_confederation_id_set(bgp, as);
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_identifier,
no_bgp_confederation_identifier_cmd,
"no bgp confederation identifier [(1-4294967295)]",
NO_STR
"BGP specific commands\n"
"AS confederation parameters\n"
"AS number\n"
"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 (1-4294967295)...",
"BGP specific commands\n"
"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++) {
as = strtoul(argv[i]->arg, NULL, 10);
if (bgp->as == as) {
vty_out(vty,
"%% Local member-AS not allowed in confed peer list\n");
continue;
}
bgp_confederation_peers_add(bgp, as);
}
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_peers,
no_bgp_confederation_peers_cmd,
"no bgp confederation peers (1-4294967295)...",
NO_STR
"BGP specific commands\n"
"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++) {
as = strtoul(argv[i]->arg, NULL, 10);
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;
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) {
THREAD_TIMER_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_update_delay_config_vty(struct vty *vty, const char *delay,
const char *wait)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
uint16_t update_delay;
uint16_t establish_wait;
update_delay = strtoul(delay, NULL, 10);
if (!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> */
establish_wait = atoi(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);
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 (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
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");
}
}
/* Update-delay configuration */
DEFUN (bgp_update_delay,
bgp_update_delay_cmd,
"update-delay (0-3600)",
"Force initial delay for best-path and updates\n"
"Seconds\n")
{
int idx_number = 1;
return bgp_update_delay_config_vty(vty, argv[idx_number]->arg, NULL);
}
DEFUN (bgp_update_delay_establish_wait,
bgp_update_delay_establish_wait_cmd,
"update-delay (0-3600) (1-3600)",
"Force initial delay for best-path and updates\n"
"Seconds\n"
"Seconds\n")
{
int idx_number = 1;
int idx_number_2 = 2;
return bgp_update_delay_config_vty(vty, argv[idx_number]->arg,
argv[idx_number_2]->arg);
}
/* Update-delay deconfiguration */
DEFUN (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"
"Seconds\n"
"Seconds\n")
{
return bgp_update_delay_deconfig_vty(vty);
}
static int bgp_wpkt_quanta_config_vty(struct vty *vty, const char *num,
char set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (set) {
uint32_t quanta = strtoul(num, NULL, 10);
atomic_store_explicit(&bgp->wpkt_quanta, quanta,
memory_order_relaxed);
} else {
atomic_store_explicit(&bgp->wpkt_quanta, BGP_WRITE_PACKET_MAX,
memory_order_relaxed);
}
return CMD_SUCCESS;
}
static int bgp_rpkt_quanta_config_vty(struct vty *vty, const char *num,
char set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (set) {
uint32_t quanta = strtoul(num, NULL, 10);
atomic_store_explicit(&bgp->rpkt_quanta, quanta,
memory_order_relaxed);
} else {
atomic_store_explicit(&bgp->rpkt_quanta, BGP_READ_PACKET_MAX,
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 */
DEFUN (bgp_wpkt_quanta,
bgp_wpkt_quanta_cmd,
"write-quanta (1-10)",
"How many packets to write to peer socket per run\n"
"Number of packets\n")
{
int idx_number = 1;
return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1);
}
DEFUN (no_bgp_wpkt_quanta,
no_bgp_wpkt_quanta_cmd,
"no write-quanta (1-10)",
NO_STR
"How many packets to write to peer socket per I/O cycle\n"
"Number of packets\n")
{
int idx_number = 2;
return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0);
}
DEFUN (bgp_rpkt_quanta,
bgp_rpkt_quanta_cmd,
"read-quanta (1-10)",
"How many packets to read from peer socket per I/O cycle\n"
"Number of packets\n")
{
int idx_number = 1;
return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1);
}
DEFUN (no_bgp_rpkt_quanta,
no_bgp_rpkt_quanta_cmd,
"no read-quanta (1-10)",
NO_STR
"How many packets to read from peer socket per I/O cycle\n"
"Number of packets\n")
{
int idx_number = 2;
return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0);
}
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);
}
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;
argv_find(argv, argc, "(0-4294967295)", &idx);
bgp->heuristic_coalesce = false;
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,
BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN, 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")
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 (CHECK_FLAG(bgp->maxpaths[afi][safi].ibgp_flags,
BGP_FLAG_IBGP_MULTIPATH_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);
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_unset(bgp);
return CMD_SUCCESS;
}
DEFUN (bgp_client_to_client_reflection,
bgp_client_to_client_reflection_cmd,
"bgp client-to-client reflection",
"BGP specific commands\n"
"Configure client to client route reflection\n"
"reflection of routes allowed\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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 specific commands\n"
"Configure client to client route reflection\n"
"reflection of routes allowed\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Allow comparing MED from different neighbors\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Allow comparing MED from different neighbors\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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 specific commands\n"
"Require in and out policy for eBGP peers (RFC8212)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_ENABLED;
return CMD_SUCCESS;
}
DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd,
"no bgp ebgp-requires-policy",
NO_STR
"BGP specific commands\n"
"Require in and out policy for eBGP peers (RFC8212)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
return CMD_SUCCESS;
}
/* "bgp deterministic-med" configuration. */
DEFUN (bgp_deterministic_med,
bgp_deterministic_med_cmd,
"bgp deterministic-med",
"BGP specific commands\n"
"Pick the best-MED path among paths advertised from the neighboring AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (!bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED)) {
bgp_flag_set(bgp, 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 specific commands\n"
"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 (bgp_flag_check(bgp, 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 {
bgp_flag_unset(bgp, BGP_FLAG_DETERMINISTIC_MED);
bgp_recalculate_all_bestpaths(bgp);
}
}
return CMD_SUCCESS;
}
/* "bgp graceful-restart" configuration. */
DEFUN (bgp_graceful_restart,
bgp_graceful_restart_cmd,
"bgp graceful-restart",
"BGP specific commands\n"
"Graceful restart capability parameters\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_RESTART);
return CMD_SUCCESS;
}
DEFUN (no_bgp_graceful_restart,
no_bgp_graceful_restart_cmd,
"no bgp graceful-restart",
NO_STR
"BGP specific commands\n"
"Graceful restart capability parameters\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_RESTART);
return CMD_SUCCESS;
}
DEFUN (bgp_graceful_restart_stalepath_time,
bgp_graceful_restart_stalepath_time_cmd,
"bgp graceful-restart stalepath-time (1-4095)",
"BGP specific commands\n"
"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 (1-4095)",
"BGP specific commands\n"
"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 (no_bgp_graceful_restart_stalepath_time,
no_bgp_graceful_restart_stalepath_time_cmd,
"no bgp graceful-restart stalepath-time [(1-4095)]",
NO_STR
"BGP specific commands\n"
"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 [(1-4095)]",
NO_STR
"BGP specific commands\n"
"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 (bgp_graceful_restart_preserve_fw,
bgp_graceful_restart_preserve_fw_cmd,
"bgp graceful-restart preserve-fw-state",
"BGP specific commands\n"
"Graceful restart capability parameters\n"
"Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Graceful restart capability parameters\n"
"Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
return CMD_SUCCESS;
}
/* "bgp graceful-shutdown" configuration */
DEFUN (bgp_graceful_shutdown,
bgp_graceful_shutdown_cmd,
"bgp graceful-shutdown",
BGP_STR
"Graceful shutdown parameters\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN);
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);
}
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")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN);
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);
}
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);
bgp_flag_unset(bgp, 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);
bgp_flag_set(bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER);
return CMD_SUCCESS;
}
/* "bgp enforce-first-as" configuration. */
#if CONFDATE > 20190517
CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
#endif
DEFUN_HIDDEN (bgp_enforce_first_as,
bgp_enforce_first_as_cmd,
"[no] bgp enforce-first-as",
NO_STR
BGP_STR
"Enforce the first AS for EBGP routes\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (strmatch(argv[0]->text, "no"))
bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
else
bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
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 specific commands\n"
"Change the default bestpath selection\n"
"Compare router-id for identical EBGP paths\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Change the default bestpath selection\n"
"Compare router-id for identical EBGP paths\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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 specific commands\n"
"Change the default bestpath selection\n"
"AS-path attribute\n"
"Ignore as-path length in selecting a route\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Change the default bestpath selection\n"
"AS-path attribute\n"
"Ignore as-path length in selecting a route\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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 specific commands\n"
"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);
bgp_flag_set(bgp, 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 specific commands\n"
"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);
bgp_flag_unset(bgp, 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 specific commands\n"
"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;
bgp_flag_set(bgp, 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))
bgp_flag_set(bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
else
bgp_flag_unset(bgp, 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 specific commands\n"
"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);
bgp_flag_unset(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX);
bgp_flag_unset(bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
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 specific commands\n"
"Log neighbor up/down and reset reason\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Log neighbor up/down and reset reason\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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 specific commands\n"
"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))
bgp_flag_set(bgp, BGP_FLAG_MED_CONFED);
idx = 0;
if (argv_find(argv, argc, "missing-as-worst", &idx))
bgp_flag_set(bgp, 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 specific commands\n"
"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))
bgp_flag_unset(bgp, BGP_FLAG_MED_CONFED);
idx = 0;
if (argv_find(argv, argc, "missing-as-worst", &idx))
bgp_flag_unset(bgp, BGP_FLAG_MED_MISSING_AS_WORST);
bgp_recalculate_all_bestpaths(bgp);
return CMD_SUCCESS;
}
/* "no bgp default ipv4-unicast". */
DEFUN (no_bgp_default_ipv4_unicast,
no_bgp_default_ipv4_unicast_cmd,
"no bgp default ipv4-unicast",
NO_STR
"BGP specific commands\n"
"Configure BGP defaults\n"
"Activate ipv4-unicast for a peer by default\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, BGP_FLAG_NO_DEFAULT_IPV4);
return CMD_SUCCESS;
}
DEFUN (bgp_default_ipv4_unicast,
bgp_default_ipv4_unicast_cmd,
"bgp default ipv4-unicast",
"BGP specific commands\n"
"Configure BGP defaults\n"
"Activate ipv4-unicast for a peer by default\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, BGP_FLAG_NO_DEFAULT_IPV4);
return CMD_SUCCESS;
}
/* Display hostname in certain command outputs */
DEFUN (bgp_default_show_hostname,
bgp_default_show_hostname_cmd,
"bgp default show-hostname",
"BGP specific commands\n"
"Configure BGP defaults\n"
"Show hostname in certain command outputs\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Configure BGP defaults\n"
"Show hostname in certain command outputs\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, BGP_FLAG_SHOW_HOSTNAME);
return CMD_SUCCESS;
}
/* "bgp network import-check" configuration. */
DEFUN (bgp_network_import_check,
bgp_network_import_check_cmd,
"bgp network import-check",
"BGP specific commands\n"
"BGP network command\n"
"Check BGP network route exists in IGP\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) {
bgp_flag_set(bgp, 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 specific commands\n"
"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 specific commands\n"
"BGP network command\n"
"Check BGP network route exists in IGP\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) {
bgp_flag_unset(bgp, 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 specific commands\n"
"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 specific commands\n"
"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 specific commands\n"
"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 specific commands\n"
"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 specific commands\n"
"Allow modifications made by out route-map\n"
"on ibgp neighbors\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (!bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
bgp_flag_set(bgp, 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 specific commands\n"
"Allow modifications made by out route-map\n"
"on ibgp neighbors\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
bgp_flag_unset(bgp, 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-5000)",
"BGP specific commands\n"
"Configure BGP defaults\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-5000)]",
"BGP specific commands\n"
"Configure BGP defaults\n"
"unset maximum number of BGP Dynamic Neighbors that can be created\n"
"Configure Dynamic Neighbors listen limit value to default\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 WORD",
"BGP specific commands\n"
"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, "WORD", &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 WORD",
NO_STR
"BGP specific commands\n"
"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, "WORD", &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;
char buf[PREFIX2STR_BUFFER];
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)) {
prefix2str(range, buf, sizeof(buf));
vty_out(vty,
" bgp listen range %s peer-group %s\n",
buf, group->name);
}
}
}
}
DEFUN (bgp_disable_connected_route_check,
bgp_disable_connected_route_check_cmd,
"bgp disable-ebgp-connected-route-check",
"BGP specific commands\n"
"Disable checking if nexthop is connected on ebgp sessions\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, 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 specific commands\n"
"Disable checking if nexthop is connected on ebgp sessions\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_unset(bgp, 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, afi_t afi, safi_t safi)
{
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 {
/* Get AS number. */
as = strtoul(as_str, NULL, 10);
}
/* 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, afi,
safi);
/* if not interface peer, check peer-group settings */
if (ret < 0 && !peer) {
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
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, afi, safi);
}
/* This peer belongs to peer group. */
switch (ret) {
case BGP_ERR_PEER_GROUP_MEMBER:
vty_out(vty,
"%% Peer-group member cannot override remote-as of peer-group\n");
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
vty_out(vty,
"%% Peer-group members must be all internal or all external\n");
return CMD_WARNING_CONFIG_FAILED;
}
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;
}
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|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, AFI_IP,
SAFI_UNICAST);
}
static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
afi_t afi, safi_t safi, 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;
union sockunion su;
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. */
as = strtoul(as_str, NULL, 10);
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,
afi, safi);
} else {
if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)
&& afi == AFI_IP && safi == SAFI_UNICAST)
peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
as_type, 0, 0, NULL);
else
peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
as_type, afi, safi, NULL);
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, &su, peer, group, &as);
}
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_interface_config,
neighbor_interface_config_cmd,
"neighbor WORD interface [peer-group WORD]",
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, AFI_IP, SAFI_UNICAST, 0,
argv[idx_peer_group_word]->arg, NULL);
else
return peer_conf_interface_get(vty, argv[idx_word]->arg, AFI_IP,
SAFI_UNICAST, 0, NULL, NULL);
}
DEFUN (neighbor_interface_config_v6only,
neighbor_interface_config_v6only_cmd,
"neighbor WORD interface v6only [peer-group WORD]",
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, AFI_IP, SAFI_UNICAST, 1,
argv[idx_peer_group_word]->arg, NULL);
return peer_conf_interface_get(vty, argv[idx_word]->arg, AFI_IP,
SAFI_UNICAST, 1, NULL, NULL);
}
DEFUN (neighbor_interface_config_remote_as,
neighbor_interface_config_remote_as_cmd,
"neighbor WORD interface remote-as <(1-4294967295)|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, AFI_IP,
SAFI_UNICAST, 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 <(1-4294967295)|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, AFI_IP,
SAFI_UNICAST, 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_delete(peer);
return CMD_SUCCESS;
}
group = peer_group_lookup(bgp, argv[idx_peer]->arg);
if (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;
peer_delete(peer);
if (other && other->status != Deleted)
peer_delete(other);
}
}
return CMD_SUCCESS;
}
DEFUN (no_neighbor_interface_config,
no_neighbor_interface_config_cmd,
"no neighbor WORD interface [v6only] [peer-group WORD] [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_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_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 <(1-4294967295)|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);
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 (1-4294967295)",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number 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;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 0, 0);
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 (1-4294967295) no-prepend",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number 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;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 1, 0);
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 (1-4294967295) no-prepend replace-as",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number 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;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 1, 1);
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 [(1-4294967295) [no-prepend [replace-as]]]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number 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 WORD",
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);
if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) {
vty_out(vty,
"%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n",
as);
return CMD_WARNING_CONFIG_FAILED;
}
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 WORD",
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 WORD",
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;
}
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 WORD",
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Member of the peer-group\n"
"Peer-group name\n")
static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
uint32_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, uint32_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,
uint32_t flag)
{
return peer_flag_modify_vty(vty, ip_str, flag, 0);
}
/* 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 (draft-ietf-idr-shutdown-06)\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 (draft-ietf-idr-shutdown-06)\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")
/* 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;
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;
return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
PEER_FLAG_CAPABILITY_ENHE);
}
static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str,
afi_t afi, safi_t safi, uint32_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, uint32_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, uint32_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_peer = 1;
int idx_send_recv = 5;
uint16_t flag = 0;
if (strmatch(argv[idx_send_recv]->text, "send"))
flag = PEER_FLAG_ORF_PREFIX_SM;
else if (strmatch(argv[idx_send_recv]->text, "receive"))
flag = PEER_FLAG_ORF_PREFIX_RM;
else if (strmatch(argv[idx_send_recv]->text, "both"))
flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM;
else {
vty_out(vty, "%% BGP invalid orf prefix-list option\n");
return CMD_WARNING_CONFIG_FAILED;
}
return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
bgp_node_safi(vty), flag);
}
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_peer = 2;
int idx_send_recv = 6;
uint16_t flag = 0;
if (strmatch(argv[idx_send_recv]->text, "send"))
flag = PEER_FLAG_ORF_PREFIX_SM;
else if (strmatch(argv[idx_send_recv]->text, "receive"))
flag = PEER_FLAG_ORF_PREFIX_RM;
else if (strmatch(argv[idx_send_recv]->text, "both"))
flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM;
else {
vty_out(vty, "%% BGP invalid orf prefix-list option\n");
return CMD_WARNING_CONFIG_FAILED;
}
return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
bgp_node_afi(vty), bgp_node_safi(vty),
flag);
}
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")
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