diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-04-03 15:54:50 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-04-03 15:54:50 +0200 |
commit | 23ee6b1cd6dc597876d91db9a015f7a633764808 (patch) | |
tree | 1f1901d6dd52eabc360fa1e5184875be06cd3b0f /proto | |
parent | a22c3e59683d0ea6c379a37f990e74a6d281ccef (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.c | 25 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 5 | ||||
-rw-r--r-- | proto/bgp/config.Y | 4 | ||||
-rw-r--r-- | proto/bgp/packets.c | 9 |
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 */ |