summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/bgp.c49
-rw-r--r--proto/bgp/bgp.h10
-rw-r--r--proto/bgp/config.Y9
-rw-r--r--proto/bgp/packets.c38
4 files changed, 95 insertions, 11 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 914935b9..b14df932 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -2000,6 +2000,21 @@ bgp_postconfig(struct proto_config *CF)
if (interior && (cf->local_role != BGP_ROLE_UNDEFINED))
log(L_WARN "BGP roles are not recommended to be used within AS confederations");
+ if (cf->require_enhanced_refresh && !(cf->enable_refresh && cf->enable_enhanced_refresh))
+ cf_warn("Enhanced refresh required but disabled");
+
+ if (cf->require_as4 && !cf->enable_as4)
+ cf_warn("AS4 support required but disabled");
+
+ if (cf->require_extended_messages && !cf->enable_extended_messages)
+ cf_warn("Extended messages required but not enabled");
+
+ if (cf->require_gr && !cf->gr_mode)
+ cf_warn("Graceful restart required but not enabled");
+
+ if (cf->require_llgr && !cf->llgr_mode)
+ cf_warn("Long-lived graceful restart required but not enabled");
+
if (cf->require_roles && (cf->local_role == BGP_ROLE_UNDEFINED))
cf_error("Local role must be set if roles are required");
@@ -2123,6 +2138,12 @@ bgp_postconfig(struct proto_config *CF)
if (cc->secondary && !cc->c.table->sorted)
cf_error("BGP with secondary option requires sorted table");
+
+ if (cc->require_ext_next_hop && !cc->ext_next_hop)
+ cf_warn("Extended next hop required but not enabled");
+
+ if (cc->require_add_path && !cc->add_path)
+ cf_warn("ADD-PATH required but not enabled");
}
}
@@ -2167,20 +2188,30 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
if (C->stale)
same = proto_configure_channel(P, &C, NULL) && same;
- if (same)
- proto_setup_mpls_map(P, RTS_BGP, 1);
+ /* Reset name counter */
+ p->dynamic_name_counter = 0;
- if (same && (p->start_state > BSS_PREPARE))
- bgp_update_bfd(p, new->bfd);
+ if (!same)
+ return 0;
/* We should update our copy of configuration ptr as old configuration will be freed */
- if (same)
- p->cf = new;
+ p->cf = new;
- /* Reset name counter */
- p->dynamic_name_counter = 0;
+ /* Check whether existing connections are compatible with required capabilities */
+ struct bgp_conn *ci = &p->incoming_conn;
+ if (((ci->state == BS_OPENCONFIRM) || (ci->state == BS_ESTABLISHED)) && !bgp_check_capabilities(ci))
+ return 0;
- return same;
+ struct bgp_conn *co = &p->outgoing_conn;
+ if (((co->state == BS_OPENCONFIRM) || (co->state == BS_ESTABLISHED)) && !bgp_check_capabilities(co))
+ return 0;
+
+ proto_setup_mpls_map(P, RTS_BGP, 1);
+
+ if (p->start_state > BSS_PREPARE)
+ bgp_update_bfd(p, new->bfd);
+
+ return 1;
}
#define TABLE(cf, NAME) ((cf)->NAME ? (cf)->NAME->table : NULL )
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 2e95037c..61127562 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -138,6 +138,13 @@ struct bgp_config {
const char *dynamic_name; /* Name pattern for dynamic BGP */
int dynamic_name_digits; /* Minimum number of digits for dynamic names */
int check_link; /* Use iface link state for liveness detection */
+ int require_refresh; /* Require remote support for route refresh [RFC 2918] */
+ int require_enhanced_refresh; /* Require remote support for enhanced route refresh [RFC 7313] */
+ int require_as4; /* Require remote support for 4B AS numbers [RFC 6793] */
+ int require_extended_messages; /* Require remote support for extended messages [RFC 8654] */
+ int require_hostname; /* Require remote support for hostname [draft] */
+ int require_gr; /* Require remote support for graceful restart [RFC 4724] */
+ int require_llgr; /* Require remote support for long-lived graceful restart [draft] */
struct bfd_options *bfd; /* Use BFD for liveness detection */
};
@@ -159,7 +166,9 @@ struct bgp_channel_config {
u8 llgr_able; /* Allow full long-lived GR for the channel */
uint llgr_time; /* Long-lived graceful restart stale time */
u8 ext_next_hop; /* Allow both IPv4 and IPv6 next hops */
+ u8 require_ext_next_hop; /* Require remote support of IPv4 NLRI with IPv6 next hops [RFC 8950] */
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
+ u8 require_add_path; /* Require remote support of ADD-PATH extension [RFC 7911] */
u8 aigp; /* AIGP is allowed on this session */
u8 aigp_originate; /* AIGP is originated automatically */
u32 cost; /* IGP cost for direct next hops */
@@ -657,6 +666,7 @@ bgp_total_aigp_metric(rte *r)
void bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new);
void bgp_prepare_capabilities(struct bgp_conn *conn);
+int bgp_check_capabilities(struct bgp_conn *conn);
const struct bgp_af_desc *bgp_get_af_desc(u32 afi);
const struct bgp_af_caps *bgp_find_af_caps(struct bgp_caps *caps, u32 afi);
void bgp_schedule_packet(struct bgp_conn *conn, struct bgp_channel *c, int type);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 6981a117..0fcbb276 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -191,6 +191,13 @@ bgp_proto:
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
| bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
+ | bgp_proto REQUIRE ROUTE REFRESH bool ';' { BGP_CFG->require_refresh = $5; }
+ | bgp_proto REQUIRE ENHANCED ROUTE REFRESH bool ';' { BGP_CFG->require_enhanced_refresh = $6; }
+ | bgp_proto REQUIRE AS4 bool ';' { BGP_CFG->require_as4 = $4; }
+ | bgp_proto REQUIRE EXTENDED MESSAGES bool ';' { BGP_CFG->require_extended_messages = $5; }
+ | bgp_proto REQUIRE HOSTNAME bool ';' { BGP_CFG->require_hostname = $4; }
+ | bgp_proto REQUIRE GRACEFUL RESTART bool ';' { BGP_CFG->require_gr = $5; }
+ | bgp_proto REQUIRE LONG LIVED GRACEFUL RESTART bool ';' { BGP_CFG->require_llgr = $7; }
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
@@ -284,9 +291,11 @@ bgp_channel_item:
| LONG LIVED GRACEFUL RESTART bool { BGP_CC->llgr_able = $5; }
| LONG LIVED STALE TIME expr { BGP_CC->llgr_time = $5; }
| EXTENDED NEXT HOP bool { BGP_CC->ext_next_hop = $4; }
+ | REQUIRE EXTENDED NEXT HOP bool { BGP_CC->require_ext_next_hop = $5; if (BGP_AFI(BGP_CC->afi) != BGP_AFI_IPV4) cf_warn("Require extended next hop option ignored for non-IPv4 channels"); }
| ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
+ | REQUIRE ADD PATHS bool { BGP_CC->require_add_path = $4; }
| IMPORT TABLE bool { BGP_CC->import_table = $3; }
| EXPORT TABLE bool { BGP_CC->export_table = $3; }
| AIGP bool { BGP_CC->aigp = $2; BGP_CC->aigp_originate = 0; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 395169a4..1e5a226f 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -694,7 +694,7 @@ err:
return -1;
}
-static int
+int
bgp_check_capabilities(struct bgp_conn *conn)
{
struct bgp_proto *p = conn->bgp;
@@ -706,6 +706,29 @@ bgp_check_capabilities(struct bgp_conn *conn)
/* This is partially overlapping with bgp_conn_enter_established_state(),
but we need to run this just after we receive OPEN message */
+ if (p->cf->require_refresh && !remote->route_refresh)
+ return 0;
+
+ if (p->cf->require_enhanced_refresh && !remote->enhanced_refresh)
+ return 0;
+
+ if (p->cf->require_as4 && !remote->as4_support)
+ return 0;
+
+ if (p->cf->require_extended_messages && !remote->ext_messages)
+ return 0;
+
+ if (p->cf->require_hostname && !remote->hostname)
+ return 0;
+
+ if (p->cf->require_gr && !remote->gr_aware)
+ return 0;
+
+ if (p->cf->require_llgr && !remote->llgr_aware)
+ return 0;
+
+ /* No check for require_roles, as it uses error code 2.11 instead of 2.7 */
+
BGP_WALK_CHANNELS(p, c)
{
const struct bgp_af_caps *loc = bgp_find_af_caps(local, c->afi);
@@ -719,7 +742,18 @@ bgp_check_capabilities(struct bgp_conn *conn)
return 0;
if (active)
+ {
+ if (c->cf->require_ext_next_hop && !rem->ext_next_hop)
+ return 0;
+
+ if (c->cf->require_add_path && (loc->add_path & BGP_ADD_PATH_RX) && !(rem->add_path & BGP_ADD_PATH_TX))
+ return 0;
+
+ if (c->cf->require_add_path && (loc->add_path & BGP_ADD_PATH_TX) && !(rem->add_path & BGP_ADD_PATH_RX))
+ return 0;
+
count++;
+ }
}
/* We need at least one channel active */
@@ -905,7 +939,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
if (!id || (p->is_internal && id == p->local_id))
{ bgp_error(conn, 2, 3, pkt+24, -4); return; }
- /* RFC 5492 4 - check for required capabilities */
+ /* RFC 5492 5 - check for required capabilities */
if (p->cf->capabilities && !bgp_check_capabilities(conn))
{ bgp_error(conn, 2, 7, NULL, 0); return; }