mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-14 09:20:34 +00:00
bgpd: Implement neighbor X remote-as auto
In some cases (large scale) it's desired to avoid changing configurations, but let the BGP to automatically handle ASN changes. `auto` means the peering can be iBGP or eBGP. It will be automatically detected and adjusted from the OPEN message. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
parent
d4758b3ccc
commit
0dfe25697f
@ -4468,6 +4468,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||||||
bgp_packet_mpattr_end(s, mpattrlen_pos);
|
bgp_packet_mpattr_end(s, mpattrlen_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(void)peer_sort(peer);
|
||||||
|
|
||||||
/* Origin attribute. */
|
/* Origin attribute. */
|
||||||
stream_putc(s, BGP_ATTR_FLAG_TRANS);
|
stream_putc(s, BGP_ATTR_FLAG_TRANS);
|
||||||
stream_putc(s, BGP_ATTR_ORIGIN);
|
stream_putc(s, BGP_ATTR_ORIGIN);
|
||||||
|
@ -1977,6 +1977,14 @@ static int bgp_open_receive(struct peer_connection *connection,
|
|||||||
BGP_NOTIFY_OPEN_BAD_PEER_AS,
|
BGP_NOTIFY_OPEN_BAD_PEER_AS,
|
||||||
notify_data_remote_as, 2);
|
notify_data_remote_as, 2);
|
||||||
return BGP_Stop;
|
return BGP_Stop;
|
||||||
|
} else if (peer->as_type == AS_AUTO) {
|
||||||
|
if (remote_as == peer->bgp->as) {
|
||||||
|
peer->as = peer->local_as;
|
||||||
|
SET_FLAG(peer->as_type, AS_INTERNAL);
|
||||||
|
} else {
|
||||||
|
peer->as = remote_as;
|
||||||
|
SET_FLAG(peer->as_type, AS_EXTERNAL);
|
||||||
|
}
|
||||||
} else if (peer->as_type == AS_INTERNAL) {
|
} else if (peer->as_type == AS_INTERNAL) {
|
||||||
if (remote_as != peer->bgp->as) {
|
if (remote_as != peer->bgp->as) {
|
||||||
if (bgp_debug_neighbor_events(peer))
|
if (bgp_debug_neighbor_events(peer))
|
||||||
|
@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
|
|||||||
|
|
||||||
key = 0;
|
key = 0;
|
||||||
|
|
||||||
key = jhash_1word(peer->sort, key); /* EBGP or IBGP */
|
/* `remote-as auto` technically uses identical peer->sort.
|
||||||
|
* After OPEN message is parsed, this is updated accordingly, but
|
||||||
|
* we need to call the peer_sort() here also to properly create
|
||||||
|
* separate subgroups.
|
||||||
|
*/
|
||||||
|
key = jhash_1word(peer_sort((struct peer *)peer), key);
|
||||||
key = jhash_1word(peer->sub_sort, key); /* OAD */
|
key = jhash_1word(peer->sub_sort, key); /* OAD */
|
||||||
key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
|
key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
|
||||||
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
|
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
|
||||||
|
@ -4871,6 +4871,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
|
|||||||
} else if (as_str[0] == 'e') {
|
} else if (as_str[0] == 'e') {
|
||||||
as = 0;
|
as = 0;
|
||||||
as_type = AS_EXTERNAL;
|
as_type = AS_EXTERNAL;
|
||||||
|
} else if (as_str[0] == 'a') {
|
||||||
|
as = 0;
|
||||||
|
as_type = AS_AUTO;
|
||||||
} else if (!asn_str2asn(as_str, &as))
|
} else if (!asn_str2asn(as_str, &as))
|
||||||
as_type = AS_UNSPECIFIED;
|
as_type = AS_UNSPECIFIED;
|
||||||
|
|
||||||
@ -4976,13 +4979,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
|
|||||||
|
|
||||||
DEFUN (neighbor_remote_as,
|
DEFUN (neighbor_remote_as,
|
||||||
neighbor_remote_as_cmd,
|
neighbor_remote_as_cmd,
|
||||||
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
|
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external|auto>",
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
NEIGHBOR_ADDR_STR2
|
NEIGHBOR_ADDR_STR2
|
||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
int idx_peer = 1;
|
int idx_peer = 1;
|
||||||
int idx_remote_as = 3;
|
int idx_remote_as = 3;
|
||||||
@ -5054,6 +5058,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
|
|||||||
as_type = AS_INTERNAL;
|
as_type = AS_INTERNAL;
|
||||||
} else if (as_str[0] == 'e') {
|
} else if (as_str[0] == 'e') {
|
||||||
as_type = AS_EXTERNAL;
|
as_type = AS_EXTERNAL;
|
||||||
|
} else if (as_str[0] == 'a') {
|
||||||
|
as_type = AS_AUTO;
|
||||||
} else {
|
} else {
|
||||||
/* Get AS number. */
|
/* Get AS number. */
|
||||||
if (asn_str2asn(as_str, &as))
|
if (asn_str2asn(as_str, &as))
|
||||||
@ -5170,14 +5176,15 @@ DEFUN (neighbor_interface_config_v6only,
|
|||||||
|
|
||||||
DEFUN (neighbor_interface_config_remote_as,
|
DEFUN (neighbor_interface_config_remote_as,
|
||||||
neighbor_interface_config_remote_as_cmd,
|
neighbor_interface_config_remote_as_cmd,
|
||||||
"neighbor WORD interface remote-as <ASNUM|internal|external>",
|
"neighbor WORD interface remote-as <ASNUM|internal|external|auto>",
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
"Interface name or neighbor tag\n"
|
"Interface name or neighbor tag\n"
|
||||||
"Enable BGP on interface\n"
|
"Enable BGP on interface\n"
|
||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
int idx_word = 1;
|
int idx_word = 1;
|
||||||
int idx_remote_as = 4;
|
int idx_remote_as = 4;
|
||||||
@ -5187,7 +5194,7 @@ DEFUN (neighbor_interface_config_remote_as,
|
|||||||
|
|
||||||
DEFUN (neighbor_interface_v6only_config_remote_as,
|
DEFUN (neighbor_interface_v6only_config_remote_as,
|
||||||
neighbor_interface_v6only_config_remote_as_cmd,
|
neighbor_interface_v6only_config_remote_as_cmd,
|
||||||
"neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
|
"neighbor WORD interface v6only remote-as <ASNUM|internal|external|auto>",
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
"Interface name or neighbor tag\n"
|
"Interface name or neighbor tag\n"
|
||||||
"Enable BGP with v6 link-local only\n"
|
"Enable BGP with v6 link-local only\n"
|
||||||
@ -5195,7 +5202,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as,
|
|||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
int idx_word = 1;
|
int idx_word = 1;
|
||||||
int idx_remote_as = 5;
|
int idx_remote_as = 5;
|
||||||
@ -5232,14 +5240,15 @@ DEFUN (neighbor_peer_group,
|
|||||||
|
|
||||||
DEFUN (no_neighbor,
|
DEFUN (no_neighbor,
|
||||||
no_neighbor_cmd,
|
no_neighbor_cmd,
|
||||||
"no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external>]>",
|
"no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external|auto>]>",
|
||||||
NO_STR
|
NO_STR
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
NEIGHBOR_ADDR_STR2
|
NEIGHBOR_ADDR_STR2
|
||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
int idx_peer = 2;
|
int idx_peer = 2;
|
||||||
@ -5310,7 +5319,7 @@ DEFUN (no_neighbor,
|
|||||||
|
|
||||||
DEFUN (no_neighbor_interface_config,
|
DEFUN (no_neighbor_interface_config,
|
||||||
no_neighbor_interface_config_cmd,
|
no_neighbor_interface_config_cmd,
|
||||||
"no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]",
|
"no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]",
|
||||||
NO_STR
|
NO_STR
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
"Interface name\n"
|
"Interface name\n"
|
||||||
@ -5321,7 +5330,8 @@ DEFUN (no_neighbor_interface_config,
|
|||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
int idx_word = 2;
|
int idx_word = 2;
|
||||||
@ -5378,14 +5388,15 @@ DEFUN (no_neighbor_peer_group,
|
|||||||
|
|
||||||
DEFUN (no_neighbor_interface_peer_group_remote_as,
|
DEFUN (no_neighbor_interface_peer_group_remote_as,
|
||||||
no_neighbor_interface_peer_group_remote_as_cmd,
|
no_neighbor_interface_peer_group_remote_as_cmd,
|
||||||
"no neighbor WORD remote-as <ASNUM|internal|external>",
|
"no neighbor WORD remote-as <ASNUM|internal|external|auto>",
|
||||||
NO_STR
|
NO_STR
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
"Interface name or neighbor tag\n"
|
"Interface name or neighbor tag\n"
|
||||||
"Specify a BGP neighbor\n"
|
"Specify a BGP neighbor\n"
|
||||||
AS_STR
|
AS_STR
|
||||||
"Internal BGP peer\n"
|
"Internal BGP peer\n"
|
||||||
"External BGP peer\n")
|
"External BGP peer\n"
|
||||||
|
"Automatically detect remote ASN\n")
|
||||||
{
|
{
|
||||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
int idx_word = 2;
|
int idx_word = 2;
|
||||||
@ -11887,7 +11898,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
|
|||||||
/* filter remote-as (internal|external) */
|
/* filter remote-as (internal|external) */
|
||||||
if (as_type != AS_UNSPECIFIED) {
|
if (as_type != AS_UNSPECIFIED) {
|
||||||
if (peer->as_type == AS_SPECIFIED) {
|
if (peer->as_type == AS_SPECIFIED) {
|
||||||
if (as_type == AS_INTERNAL) {
|
if (CHECK_FLAG(as_type, AS_INTERNAL)) {
|
||||||
if (peer->as != peer->local_as)
|
if (peer->as != peer->local_as)
|
||||||
return true;
|
return true;
|
||||||
} else if (peer->as == peer->local_as)
|
} else if (peer->as == peer->local_as)
|
||||||
@ -12879,6 +12890,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
|
|||||||
as_type = AS_INTERNAL;
|
as_type = AS_INTERNAL;
|
||||||
else if (argv[idx + 1]->arg[0] == 'e')
|
else if (argv[idx + 1]->arg[0] == 'e')
|
||||||
as_type = AS_EXTERNAL;
|
as_type = AS_EXTERNAL;
|
||||||
|
else if (argv[idx + 1]->arg[0] == 'a')
|
||||||
|
as_type = AS_AUTO;
|
||||||
else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
|
else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Invalid neighbor remote-as value: %s\n",
|
"%% Invalid neighbor remote-as value: %s\n",
|
||||||
@ -14002,9 +14015,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
|
|||||||
json_object_boolean_true_add(json_neigh,
|
json_object_boolean_true_add(json_neigh,
|
||||||
"localAsReplaceAs");
|
"localAsReplaceAs");
|
||||||
} else {
|
} else {
|
||||||
if ((p->as_type == AS_SPECIFIED) ||
|
if (p->as_type == AS_SPECIFIED ||
|
||||||
(p->as_type == AS_EXTERNAL) ||
|
CHECK_FLAG(p->as_type, AS_AUTO) ||
|
||||||
(p->as_type == AS_INTERNAL)) {
|
CHECK_FLAG(p->as_type, AS_EXTERNAL) ||
|
||||||
|
CHECK_FLAG(p->as_type, AS_INTERNAL)) {
|
||||||
vty_out(vty, "remote AS ");
|
vty_out(vty, "remote AS ");
|
||||||
vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
|
vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
|
||||||
vty_out(vty, ", ");
|
vty_out(vty, ", ");
|
||||||
@ -14023,7 +14037,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
|
|||||||
: "");
|
: "");
|
||||||
}
|
}
|
||||||
/* peer type internal or confed-internal */
|
/* peer type internal or confed-internal */
|
||||||
if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) {
|
if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) {
|
||||||
if (use_json) {
|
if (use_json) {
|
||||||
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
|
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
|
||||||
json_object_boolean_true_add(
|
json_object_boolean_true_add(
|
||||||
@ -17011,7 +17025,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
|
|||||||
&conf->as);
|
&conf->as);
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
} else if (conf->as_type == AS_INTERNAL) {
|
} else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
|
||||||
if (json)
|
if (json)
|
||||||
asn_asn2json(json, "remoteAs", group->bgp->as,
|
asn_asn2json(json, "remoteAs", group->bgp->as,
|
||||||
group->bgp->asnotation);
|
group->bgp->asnotation);
|
||||||
@ -17023,7 +17037,8 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
|
|||||||
vty_out(vty, "\nBGP peer-group %s\n", group->name);
|
vty_out(vty, "\nBGP peer-group %s\n", group->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) {
|
if ((group->bgp->as == conf->as) ||
|
||||||
|
CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
|
||||||
if (json)
|
if (json)
|
||||||
json_object_string_add(json_peer_group, "type",
|
json_object_string_add(json_peer_group, "type",
|
||||||
"internal");
|
"internal");
|
||||||
@ -18525,6 +18540,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
|
|||||||
} else if (peer->as_type == AS_EXTERNAL) {
|
} else if (peer->as_type == AS_EXTERNAL) {
|
||||||
vty_out(vty, " remote-as external");
|
vty_out(vty, " remote-as external");
|
||||||
if_ras_printed = true;
|
if_ras_printed = true;
|
||||||
|
} else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
|
||||||
|
vty_out(vty, " remote-as auto");
|
||||||
|
if_ras_printed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
@ -18547,6 +18565,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" neighbor %s remote-as external\n",
|
" neighbor %s remote-as external\n",
|
||||||
addr);
|
addr);
|
||||||
|
} else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
|
||||||
|
vty_out(vty, " neighbor %s remote-as auto\n",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18576,6 +18597,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" neighbor %s remote-as external\n",
|
" neighbor %s remote-as external\n",
|
||||||
addr);
|
addr);
|
||||||
|
} else if (CHECK_FLAG(peer->as_type, AS_AUTO)) {
|
||||||
|
vty_out(vty, " neighbor %s remote-as auto\n",
|
||||||
|
addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
bgpd/bgpd.c
25
bgpd/bgpd.c
@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
|
|||||||
|
|
||||||
/* Peer-group */
|
/* Peer-group */
|
||||||
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
|
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
|
||||||
if (peer->as_type == AS_INTERNAL)
|
if (CHECK_FLAG(peer->as_type, AS_INTERNAL))
|
||||||
return BGP_PEER_IBGP;
|
return BGP_PEER_IBGP;
|
||||||
|
|
||||||
else if (peer->as_type == AS_EXTERNAL)
|
if (CHECK_FLAG(peer->as_type, AS_EXTERNAL))
|
||||||
return BGP_PEER_EBGP;
|
return BGP_PEER_EBGP;
|
||||||
|
|
||||||
else if (peer->as_type == AS_SPECIFIED && peer->as) {
|
else if (peer->as_type == AS_SPECIFIED && peer->as) {
|
||||||
@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
|
|||||||
return BGP_PEER_IBGP;
|
return BGP_PEER_IBGP;
|
||||||
else
|
else
|
||||||
return BGP_PEER_EBGP;
|
return BGP_PEER_EBGP;
|
||||||
} else if (peer->group->conf->as_type
|
} else if (CHECK_FLAG(peer->group->conf->as_type,
|
||||||
== AS_INTERNAL)
|
AS_INTERNAL))
|
||||||
return BGP_PEER_IBGP;
|
return BGP_PEER_IBGP;
|
||||||
else
|
else
|
||||||
return BGP_PEER_EBGP;
|
return BGP_PEER_EBGP;
|
||||||
}
|
}
|
||||||
/* no AS information anywhere, let caller know */
|
/* no AS information anywhere, let caller know */
|
||||||
return BGP_PEER_UNSPECIFIED;
|
return BGP_PEER_UNSPECIFIED;
|
||||||
} else if (peer->as_type != AS_SPECIFIED)
|
} else if (peer->as_type != AS_SPECIFIED) {
|
||||||
return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
|
if (CHECK_FLAG(peer->as_type, AS_INTERNAL))
|
||||||
: BGP_PEER_EBGP);
|
return BGP_PEER_IBGP;
|
||||||
|
else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL))
|
||||||
|
return BGP_PEER_EBGP;
|
||||||
|
}
|
||||||
|
|
||||||
return (local_as == 0 ? BGP_PEER_INTERNAL
|
return (local_as == 0 ? BGP_PEER_INTERNAL
|
||||||
: local_as == peer->as ? BGP_PEER_IBGP
|
: local_as == peer->as ? BGP_PEER_IBGP
|
||||||
@ -2201,10 +2204,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* internal/external used, compare as-types */
|
/* internal/external used, compare as-types */
|
||||||
if (((peer_sort_type == BGP_PEER_IBGP)
|
if (((peer_sort_type == BGP_PEER_IBGP) &&
|
||||||
&& (as_type != AS_INTERNAL))
|
!CHECK_FLAG(as_type, AS_INTERNAL)) ||
|
||||||
|| ((peer_sort_type == BGP_PEER_EBGP)
|
((peer_sort_type == BGP_PEER_EBGP) &&
|
||||||
&& (as_type != AS_EXTERNAL))) {
|
!CHECK_FLAG(as_type, AS_EXTERNAL))) {
|
||||||
*as = peer->as;
|
*as = peer->as;
|
||||||
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
|
return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
|
||||||
}
|
}
|
||||||
|
10
bgpd/bgpd.h
10
bgpd/bgpd.h
@ -56,10 +56,12 @@ struct bgp_pbr_config;
|
|||||||
* behavior
|
* behavior
|
||||||
* in the system.
|
* in the system.
|
||||||
*/
|
*/
|
||||||
enum { AS_UNSPECIFIED = 0,
|
enum peer_asn_type {
|
||||||
AS_SPECIFIED,
|
AS_UNSPECIFIED = 1,
|
||||||
AS_INTERNAL,
|
AS_SPECIFIED = 2,
|
||||||
AS_EXTERNAL,
|
AS_INTERNAL = 4,
|
||||||
|
AS_EXTERNAL = 8,
|
||||||
|
AS_AUTO = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Zebra Gracaful Restart states */
|
/* Zebra Gracaful Restart states */
|
||||||
|
@ -1561,6 +1561,10 @@ Defining Peers
|
|||||||
peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN`
|
peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN`
|
||||||
command the connection will be denied.
|
command the connection will be denied.
|
||||||
|
|
||||||
|
.. clicmd:: neighbor PEER remote-as auto
|
||||||
|
|
||||||
|
The neighbor's ASN is detected automatically from the OPEN message.
|
||||||
|
|
||||||
.. clicmd:: neighbor PEER oad
|
.. clicmd:: neighbor PEER oad
|
||||||
|
|
||||||
Mark a peer belonging to the One Administrative Domain.
|
Mark a peer belonging to the One Administrative Domain.
|
||||||
@ -1699,7 +1703,7 @@ Configuring Peers
|
|||||||
IPv4 session addresses, see the ``neighbor PEER update-source`` command
|
IPv4 session addresses, see the ``neighbor PEER update-source`` command
|
||||||
below.
|
below.
|
||||||
|
|
||||||
.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN>
|
.. clicmd:: neighbor PEER interface remote-as <internal|external|auto|ASN>
|
||||||
|
|
||||||
Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
|
Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
|
||||||
session will be established via IPv6 link locals. Use ``internal`` for iBGP
|
session will be established via IPv6 link locals. Use ``internal`` for iBGP
|
||||||
|
0
tests/topotests/bgp_remote_as_auto/__init__.py
Normal file
0
tests/topotests/bgp_remote_as_auto/__init__.py
Normal file
17
tests/topotests/bgp_remote_as_auto/r1/frr.conf
Normal file
17
tests/topotests/bgp_remote_as_auto/r1/frr.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
!
|
||||||
|
int r1-eth0
|
||||||
|
ip address 192.168.1.1/24
|
||||||
|
!
|
||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.1.2 remote-as auto
|
||||||
|
neighbor 192.168.1.2 timers 1 3
|
||||||
|
neighbor 192.168.1.2 timers connect 1
|
||||||
|
neighbor 192.168.1.3 remote-as auto
|
||||||
|
neighbor 192.168.1.3 timers 1 3
|
||||||
|
neighbor 192.168.1.3 timers connect 1
|
||||||
|
address-family ipv4 unicast
|
||||||
|
network 10.0.0.1/32
|
||||||
|
exit-address-family
|
||||||
|
!
|
10
tests/topotests/bgp_remote_as_auto/r2/frr.conf
Normal file
10
tests/topotests/bgp_remote_as_auto/r2/frr.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
int r2-eth0
|
||||||
|
ip address 192.168.1.2/24
|
||||||
|
!
|
||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 192.168.1.1 remote-as auto
|
||||||
|
neighbor 192.168.1.1 timers 1 3
|
||||||
|
neighbor 192.168.1.1 timers connect 1
|
||||||
|
!
|
10
tests/topotests/bgp_remote_as_auto/r3/frr.conf
Normal file
10
tests/topotests/bgp_remote_as_auto/r3/frr.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
int r3-eth0
|
||||||
|
ip address 192.168.1.3/24
|
||||||
|
!
|
||||||
|
router bgp 65003
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 192.168.1.1 remote-as auto
|
||||||
|
neighbor 192.168.1.1 timers 1 3
|
||||||
|
neighbor 192.168.1.1 timers connect 1
|
||||||
|
!
|
130
tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py
Normal file
130
tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# SPDX-License-Identifier: ISC
|
||||||
|
|
||||||
|
# Copyright (c) 2024 by
|
||||||
|
# Donatas Abraitis <donatas@opensourcerouting.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import functools
|
||||||
|
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(os.path.join(CWD, "../"))
|
||||||
|
|
||||||
|
# pylint: disable=C0413
|
||||||
|
from lib import topotest
|
||||||
|
from lib.topogen import Topogen, get_topogen
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.bgpd]
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
topodef = {"s1": ("r1", "r2", "r3")}
|
||||||
|
tgen = Topogen(topodef, mod.__name__)
|
||||||
|
tgen.start_topology()
|
||||||
|
|
||||||
|
router_list = tgen.routers()
|
||||||
|
|
||||||
|
for _, (rname, router) in enumerate(router_list.items(), 1):
|
||||||
|
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
|
||||||
|
|
||||||
|
tgen.start_router()
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module(mod):
|
||||||
|
tgen = get_topogen()
|
||||||
|
tgen.stop_topology()
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_remote_as_auto():
|
||||||
|
tgen = get_topogen()
|
||||||
|
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
r1 = tgen.gears["r1"]
|
||||||
|
r2 = tgen.gears["r2"]
|
||||||
|
r3 = tgen.gears["r3"]
|
||||||
|
|
||||||
|
def _bgp_converge():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json"))
|
||||||
|
expected = {
|
||||||
|
"peers": {
|
||||||
|
"192.168.1.2": {
|
||||||
|
"hostname": "r2",
|
||||||
|
"remoteAs": 65001,
|
||||||
|
"localAs": 65001,
|
||||||
|
"state": "Established",
|
||||||
|
},
|
||||||
|
"192.168.1.3": {
|
||||||
|
"hostname": "r3",
|
||||||
|
"remoteAs": 65003,
|
||||||
|
"localAs": 65001,
|
||||||
|
"state": "Established",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_bgp_converge,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "Can't see automatic iBGP/eBGP peerings"
|
||||||
|
|
||||||
|
def _bgp_converge_internal():
|
||||||
|
output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"aspath": {
|
||||||
|
"string": "Local",
|
||||||
|
},
|
||||||
|
"valid": True,
|
||||||
|
"peer": {
|
||||||
|
"hostname": "r1",
|
||||||
|
"type": "internal",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_bgp_converge_internal,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "Can't see automatic iBGP peering"
|
||||||
|
|
||||||
|
def _bgp_converge_external():
|
||||||
|
output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"aspath": {
|
||||||
|
"string": "65001",
|
||||||
|
},
|
||||||
|
"valid": True,
|
||||||
|
"peer": {
|
||||||
|
"hostname": "r1",
|
||||||
|
"type": "external",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_bgp_converge_external,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "Can't see automatic eBGP peering"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user