}
/* Check neighbor as number. */
- if (remote_as != peer->as)
+ if (peer->as_type == AS_INTERNAL)
+ {
+ if (remote_as != peer->bgp->as)
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s bad OPEN, remote AS is %u, internal specified",
+ peer->host, remote_as);
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_BAD_PEER_AS,
+ notify_data_remote_as, 2);
+ return -1;
+ }
+ peer->as = peer->local_as;
+ }
+ else if (peer->as_type == AS_EXTERNAL)
+ {
+ if (remote_as == peer->bgp->as)
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s bad OPEN, remote AS is %u, external specified",
+ peer->host, remote_as);
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_BAD_PEER_AS,
+ notify_data_remote_as, 2);
+ return -1;
+ }
+ peer->as = remote_as;
+ }
+ else if ((peer->as_type == AS_SPECIFIED) && (remote_as != peer->as))
{
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
+ peer->host, remote_as, peer->as);
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as, 2);
return -1;
int ret;
struct bgp *bgp;
as_t as;
+ int as_type = AS_SPECIFIED;
union sockunion su;
bgp = vty->index;
- /* Get AS number. */
- VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, BGP_AS4_MAX);
+ if (strncmp(as_str, "internal", strlen("internal")) == 0)
+ {
+ as = 0;
+ as_type = AS_INTERNAL;
+ }
+ else if (strncmp(as_str, "external", strlen("external")) == 0)
+ {
+ as = 0;
+ as_type = AS_EXTERNAL;
+ }
+ else
+ {
+ /* Get AS number. */
+ VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, BGP_AS4_MAX);
+ }
/* If peer is peer group, call proper function. */
ret = str2sockunion (peer_str, &su);
if (ret < 0)
{
/* Check for peer by interface */
- ret = peer_remote_as (bgp, NULL, peer_str, &as, afi, safi);
+ ret = peer_remote_as (bgp, NULL, peer_str, &as, as_type, afi, safi);
if (ret < 0)
{
- ret = peer_group_remote_as (bgp, peer_str, &as);
+ ret = peer_group_remote_as (bgp, peer_str, &as, as_type);
if (ret < 0)
{
vty_out (vty, "%% Create the peer-group or interface first%s",
VTY_NEWLINE);
return CMD_WARNING;
}
- ret = peer_remote_as (bgp, &su, NULL, &as, afi, safi);
+ ret = peer_remote_as (bgp, &su, NULL, &as, as_type, afi, safi);
}
/* This peer belongs to peer group. */
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
- NEIGHBOR_CMD2 "remote-as " CMD_AS_RANGE,
+ NEIGHBOR_CMD2 "remote-as (" CMD_AS_RANGE "|external|internal)",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
ALIAS (no_neighbor,
no_neighbor_remote_as_cmd,
- NO_NEIGHBOR_CMD "remote-as " CMD_AS_RANGE,
+ NO_NEIGHBOR_CMD "remote-as (" CMD_AS_RANGE "|internal|external)",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR
DEFUN (no_neighbor_interface_peer_group_remote_as,
no_neighbor_interface_peer_group_remote_as_cmd,
- "no neighbor WORD remote-as " CMD_AS_RANGE,
+ "no neighbor WORD remote-as (" CMD_AS_RANGE "|internal|external)",
NO_STR
NEIGHBOR_STR
"Interface name or neighbor tag\n"
peer = peer_lookup_by_conf_if (vty->index, argv[0]);
if (peer)
{
- peer_as_change (peer, 0);
+ peer_as_change (peer, 0, AS_SPECIFIED);
return CMD_SUCCESS;
}
conf = group->conf;
+ if (conf->as_type == AS_SPECIFIED ||
+ conf->as_type == AS_EXTERNAL) {
vty_out (vty, "%sBGP peer-group %s, remote AS %d%s",
VTY_NEWLINE, group->name, conf->as, VTY_NEWLINE);
+ } else if (conf->as_type == AS_INTERNAL) {
+ vty_out (vty, "%sBGP peer-group %s, remote AS %d%s",
+ VTY_NEWLINE, group->name, group->bgp->as, VTY_NEWLINE);
+ }
- if (group->bgp->as == conf->as)
+ if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL))
vty_out (vty, " Peer-group type is internal%s", VTY_NEWLINE);
else
vty_out (vty, " Peer-group type is external%s", VTY_NEWLINE);
/* Peer-group */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->as)
+ if (peer->as_type != AS_SPECIFIED)
+ return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+ else if (peer->as)
return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP);
else
{
}
else
{
+ if (peer->as_type != AS_SPECIFIED)
+ return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+
return (peer->local_as == 0
? BGP_PEER_INTERNAL : peer->local_as == peer->as
? BGP_PEER_IBGP : BGP_PEER_EBGP);
/* Create new BGP peer. */
struct peer *
peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
- as_t local_as, as_t remote_as, afi_t afi, safi_t safi)
+ as_t local_as, as_t remote_as, int as_type, afi_t afi, safi_t safi)
{
int active;
struct peer *peer;
}
peer->local_as = local_as;
peer->as = remote_as;
+ peer->as_type = as_type;
peer->local_id = bgp->router_id;
peer->v_holdtime = bgp->default_holdtime;
peer->v_keepalive = bgp->default_keepalive;
{
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, 0, 0, 0);
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, AS_SPECIFIED, 0, 0, 0);
else
- peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, afi, safi);
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, AS_SPECIFIED, 0, afi, safi);
}
/* Change peer's AS number. */
void
-peer_as_change (struct peer *peer, as_t as)
+peer_as_change (struct peer *peer, as_t as, int as_specified)
{
bgp_peer_sort_t type;
struct peer *conf;
}
type = peer_sort (peer);
peer->as = as;
+ peer->as_type = as_specified;
if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION)
&& ! bgp_confederation_peers_check (peer->bgp, as)
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int
-peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if, as_t *as,
- afi_t afi, safi_t safi)
+peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if,
+ as_t *as, int as_type, afi_t afi, safi_t safi)
{
struct peer *peer;
as_t local_as;
}
if (peer_sort (peer->group->conf) == BGP_PEER_IBGP)
{
- if (bgp->as != *as)
+ if ((as_type != AS_INTERNAL) && (bgp->as != *as))
{
*as = peer->as;
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
}
else
{
- if (bgp->as == *as)
+ if ((as_type != AS_EXTERNAL) && (bgp->as == *as))
{
*as = peer->as;
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
/* Existing peer's AS number change. */
if (peer->as != *as)
- peer_as_change (peer, *as);
+ peer_as_change (peer, *as, as_type);
}
else
{
if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
&& afi == AFI_IP && safi == SAFI_UNICAST)
- peer = peer_create (su, conf_if, bgp, local_as, *as, 0, 0);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, as_type, 0, 0);
else
- peer = peer_create (su, conf_if, bgp, local_as, *as, afi, safi);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, as_type, afi, safi);
}
return 0;
/* Peer group's remote AS configuration. */
int
-peer_group_remote_as (struct bgp *bgp, const char *group_name, as_t *as)
+peer_group_remote_as (struct bgp *bgp, const char *group_name,
+ as_t *as, int as_type)
{
struct peer_group *group;
struct peer *peer;
if (! group)
return -1;
- if (group->conf->as == *as)
+ if ((as_type == group->conf->as_type) && (group->conf->as == *as))
return 0;
+
/* When we setup peer-group AS number all peer group member's AS
number must be updated to same number. */
- peer_as_change (group->conf, *as);
+ peer_as_change (group->conf, *as, as_type);
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
if (peer->as != *as)
- peer_as_change (peer, *as);
+ peer_as_change (peer, *as, as_type);
}
return 0;
struct peer *peer, *other;
struct listnode *node, *nnode;
- if (! group->conf->as)
+ if ((group->conf->as_type == AS_UNSPECIFIED) ||
+ ((! group->conf->as) && (group->conf->as_type == AS_SPECIFIED)))
return 0;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
list_delete_all_node (group->peer);
group->conf->as = 0;
+ group->conf->as_type = AS_UNSPECIFIED;
return 0;
}
/* Create a new peer. */
if (! peer)
{
- if (! group->conf->as)
+ if ((group->conf->as_type == AS_SPECIFIED) && (! group->conf->as)) {
return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
+ }
- peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, afi, safi);
+ peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, group->conf->as_type, afi, safi);
peer->group = group;
peer->af_group[afi][safi] = 1;
&& strcmp (peer->group->name, group->name) != 0)
return BGP_ERR_PEER_GROUP_MISMATCH;
+ if (peer->as_type == AS_UNSPECIFIED)
+ {
+ peer->as_type = group->conf->as_type;
+ peer->as = group->conf->as;
+ }
+
if (! group->conf->as)
{
if (peer_sort (group->conf) != BGP_PEER_INTERNAL
as_t as;
/* Create peer first; we've already checked group config is valid. */
- peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, 0, 0);
+ peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, group->conf->as_type, 0, 0);
if (!peer)
return NULL;
char buf1[SU_ADDRSTRLEN];
prefix = sockunion2hostprefix(su);
- if (!prefix)
+ if (!prefix) {
return NULL;
+ }
/* See if incoming connection matches a configured listen range. */
group = peer_group_lookup_dynamic_neighbor (bgp, prefix, &listen_range);
if (! group)
return NULL;
+
gbgp = group->bgp;
if (! gbgp)
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
vty_out (vty, " neighbor %s peer-group%s", addr,
VTY_NEWLINE);
- if (peer->as)
- vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
+ if (peer->as_type == AS_SPECIFIED)
+ {
+ vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
+ VTY_NEWLINE);
+ }
+ else if (peer->as_type == AS_INTERNAL)
+ {
+ vty_out (vty, " neighbor %s remote-as internal%s", addr, VTY_NEWLINE);
+ }
+ else if (peer->as_type == AS_EXTERNAL)
+ {
+ vty_out (vty, " neighbor %s remote-as external%s", addr, VTY_NEWLINE);
+ }
}
else
{
if (! g_peer->as)
- vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
+ {
+ if (g_peer->as_type == AS_SPECIFIED)
+ vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
+ VTY_NEWLINE);
+ }
if (peer->af_group[AFI_IP][SAFI_UNICAST])
vty_out (vty, " neighbor %s peer-group %s%s", addr,
peer->group->name, VTY_NEWLINE);
struct update_subgroup;
struct bpacket;
+/*
+ * Allow the neighbor XXXX remote-as to take internal or external
+ * AS_SPECIFIED is zero to auto-inherit original non-feature/enhancement behavior
+ * in the system.
+ */
+enum {
+ AS_UNSPECIFIED = 0,
+ AS_SPECIFIED,
+ AS_INTERNAL,
+ AS_EXTERNAL,
+};
+
/* Typedef BGP specific types. */
typedef u_int32_t as_t;
typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
struct peer_af *peer_af_array[BGP_AF_MAX];
/* Peer's remote AS number. */
- as_t as;
+ int as_type;
+ as_t as;
/* Peer's local AS number. */
as_t local_as;
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);
extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
- as_t, as_t, afi_t, safi_t);
+ as_t, as_t, int, afi_t, safi_t);
extern struct peer *peer_create_accept (struct bgp *);
extern void peer_xfer_config (struct peer *dst, struct peer *src);
extern char *peer_uptime (time_t, char *, size_t);
extern int bgp_update_delay_active (struct bgp *);
extern int bgp_update_delay_configured (struct bgp *);
extern int peer_rsclient_active (struct peer *);
-extern void peer_as_change (struct peer *, as_t);
+extern void peer_as_change (struct peer *, as_t, int);
extern int peer_remote_as (struct bgp *, union sockunion *,const char *, as_t *,
- afi_t, safi_t);
-extern int peer_group_remote_as (struct bgp *, const char *, as_t *);
+ int, afi_t, safi_t);
+extern int peer_group_remote_as (struct bgp *, const char *, as_t *, int);
extern int peer_delete (struct peer *peer);
extern int peer_group_delete (struct peer_group *);
extern int peer_group_remote_as_delete (struct peer_group *);