BGP: Promiscuous ASN mode

Allow to specify just 'internal' or 'external' for remote neighbor
instead of specific ASN. In the second case that means BGP peers with
any non-local ASNs are accepted.
This commit is contained in:
Ondrej Zajicek (work) 2019-04-03 15:54:50 +02:00
parent a22c3e5968
commit 23ee6b1cd6
5 changed files with 42 additions and 12 deletions

View file

@ -2195,12 +2195,15 @@ using the following configuration parameters:
<cf/local 10.0.0.1; local as 65000;/ are valid). This parameter is
mandatory.
<tag><label id="bgp-neighbor">neighbor [<m/ip/] [port <m/number/] [as <m/number/]</tag>
<tag><label id="bgp-neighbor">neighbor [<m/ip/] [port <m/number/] [as <m/number/] [internal|external]</tag>
Define neighboring router this instance will be talking to and what AS
it is located in. In case the neighbor is in the same AS as we are, we
automatically switch to iBGP. Optionally, the remote port may also be
specified. Like <cf/local/ parameter, this parameter may also be used
multiple times with different sub-options. This parameter is mandatory.
automatically switch to IBGP. Alternatively, it is possible to specify
just <cf/internal/ or </cf/external/ instead of AS number, in that case
either local AS number, or any external AS number is accepted.
Optionally, the remote port may also be specified. Like <cf/local/
parameter, this parameter may also be used multiple times with different
sub-options. This parameter is mandatory.
<tag><label id="bgp-iface">interface <m/string/</tag>
Define interface we should use for link-local BGP IPv6 sessions.

View file

@ -507,6 +507,10 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
if (ipa_zero(p->local_ip))
p->local_ip = conn->sk->saddr;
/* For promiscuous sessions */
if (!p->remote_as)
p->remote_as = conn->received_as;
/* In case of LLv6 is not valid during BGP start */
if (ipa_zero(p->link_addr) && p->neigh && p->neigh->iface && p->neigh->iface->llv6)
p->link_addr = p->neigh->iface->llv6->ip;
@ -1754,14 +1758,19 @@ void
bgp_postconfig(struct proto_config *CF)
{
struct bgp_config *cf = (void *) CF;
int internal = (cf->local_as == cf->remote_as);
int interior = internal || cf->confederation_member;
/* Do not check templates at all */
if (cf->c.class == SYM_TEMPLATE)
return;
/* Handle undefined remote_as, zero should mean unspecified external */
if (!cf->remote_as && (cf->peer_type == BGP_PT_INTERNAL))
cf->remote_as = cf->local_as;
int internal = (cf->local_as == cf->remote_as);
int interior = internal || cf->confederation_member;
/* EBGP direct by default, IBGP multihop by default */
if (cf->multihop < 0)
cf->multihop = internal ? 64 : 0;
@ -1781,8 +1790,14 @@ bgp_postconfig(struct proto_config *CF)
if (ipa_zero(cf->remote_ip))
cf_error("Neighbor must be configured");
if (!cf->remote_as)
cf_error("Remote AS number must be set");
if (!cf->remote_as && !cf->peer_type)
cf_error("Remote AS number (or peer type) must be set");
if ((cf->peer_type == BGP_PT_INTERNAL) && !internal)
cf_error("IBGP cannot have different ASNs");
if ((cf->peer_type == BGP_PT_EXTERNAL) && internal)
cf_error("EBGP cannot have the same ASNs");
if (!cf->iface && (ipa_is_link_local(cf->local_ip) ||
ipa_is_link_local(cf->remote_ip)))
@ -2242,7 +2257,7 @@ bgp_show_proto_info(struct proto *P)
cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p));
cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
cli_msg(-1006, " Neighbor AS: %u", p->cf->remote_as);
cli_msg(-1006, " Neighbor AS: %u", p->cf->remote_as ?: p->remote_as);
if (p->gr_active_num)
cli_msg(-1006, " Neighbor graceful restart active");

View file

@ -83,6 +83,7 @@ struct bgp_config {
struct iface *iface; /* Interface for link-local addresses */
u16 local_port; /* Local listening port */
u16 remote_port; /* Neighbor destination port */
int peer_type; /* Internal or external BGP (BGP_PT_*, optional) */
int multihop; /* Number of hops if multihop */
int strict_bind; /* Bind listening socket to local address */
int ttl_security; /* Enable TTL security [RFC 5082] */
@ -152,6 +153,9 @@ struct bgp_channel_config {
struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
};
#define BGP_PT_INTERNAL 1
#define BGP_PT_EXTERNAL 2
#define NH_NO 0
#define NH_ALL 1
#define NH_IBGP 2
@ -237,6 +241,7 @@ struct bgp_conn {
u8 state; /* State of connection state machine */
u8 as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */
u8 ext_messages; /* Session uses extended message length */
u32 received_as; /* ASN received in OPEN message */
struct bgp_caps *local_caps;
struct bgp_caps *remote_caps;

View file

@ -29,7 +29,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY)
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL)
%type <i> bgp_nh
%type <i32> bgp_afi
@ -82,6 +82,8 @@ bgp_nbr_opts:
/* empty */
| bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); }
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
| bgp_nbr_opts INTERNAL { BGP_CFG->peer_type = BGP_PT_INTERNAL; }
| bgp_nbr_opts EXTERNAL { BGP_CFG->peer_type = BGP_PT_EXTERNAL; }
;
bgp_cease_mask:

View file

@ -732,13 +732,18 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
if ((as4 != asn) && (asn != AS_TRANS))
log(L_WARN "%s: Peer advertised inconsistent AS numbers", p->p.name);
if (as4 != p->remote_as)
/* When remote ASN is unspecified, it must be external one */
if (p->remote_as ? (as4 != p->remote_as) : (as4 == p->local_as))
{ as4 = htonl(as4); bgp_error(conn, 2, 2, (byte *) &as4, 4); return; }
conn->received_as = as4;
}
else
{
if (asn != p->remote_as)
if (p->remote_as ? (asn != p->remote_as) : (asn == p->local_as))
{ bgp_error(conn, 2, 2, pkt+20, 2); return; }
conn->received_as = asn;
}
/* Check the other connection */