summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2019-04-03 15:54:50 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2019-04-03 15:54:50 +0200
commit23ee6b1cd6dc597876d91db9a015f7a633764808 (patch)
tree1f1901d6dd52eabc360fa1e5184875be06cd3b0f /proto
parenta22c3e59683d0ea6c379a37f990e74a6d281ccef (diff)
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.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/bgp.c25
-rw-r--r--proto/bgp/bgp.h5
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/bgp/packets.c9
4 files changed, 35 insertions, 8 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 756f0326..92f41ef6 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -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");
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 512410d4..fd515cbb 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -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;
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 9dea78ca..c9a6af96 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -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:
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index fc572a21..0e142a7a 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -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 */