summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_route.c48
-rw-r--r--bgpd/bgp_route.h2
-rw-r--r--bgpd/bgp_vty.c53
-rw-r--r--bgpd/bgpd.c6
-rw-r--r--bgpd/bgpd.h5
5 files changed, 114 insertions, 0 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 59ca223a2d..d02d747361 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1224,6 +1224,20 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
}
}
+ /* RFC 8212 to prevent route leaks.
+ * This specification intends to improve this situation by requiring the
+ * explicit configuration of both BGP Import and Export Policies for any
+ * External BGP (EBGP) session such as customers, peers, or
+ * confederation boundaries for all enabled address families. Through
+ * codification of the aforementioned requirement, operators will
+ * benefit from consistent behavior across different BGP
+ * implementations.
+ */
+ if (peer->bgp->ebgp_requires_policy
+ == DEFAULT_EBGP_POLICY_ENABLED)
+ if (!bgp_inbound_policy_exists(peer, filter))
+ return RMAP_DENY;
+
/* Route map apply. */
if (rmap) {
memset(&rmap_path, 0, sizeof(struct bgp_path_info));
@@ -1777,6 +1791,20 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
}
}
+ /* RFC 8212 to prevent route leaks.
+ * This specification intends to improve this situation by requiring the
+ * explicit configuration of both BGP Import and Export Policies for any
+ * External BGP (EBGP) session such as customers, peers, or
+ * confederation boundaries for all enabled address families. Through
+ * codification of the aforementioned requirement, operators will
+ * benefit from consistent behavior across different BGP
+ * implementations.
+ */
+ if (peer->bgp->ebgp_requires_policy
+ == DEFAULT_EBGP_POLICY_ENABLED)
+ if (!bgp_outbound_policy_exists(peer, filter))
+ return 0;
+
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
if (peer->sort == BGP_PEER_IBGP
|| peer->sort == BGP_PEER_CONFED) {
@@ -4160,6 +4188,26 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
}
}
+int bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
+{
+ if (peer->sort == BGP_PEER_EBGP
+ && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter)
+ || FILTER_LIST_OUT_NAME(filter)
+ || DISTRIBUTE_OUT_NAME(filter)))
+ return 1;
+ return 0;
+}
+
+int bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
+{
+ if (peer->sort == BGP_PEER_EBGP
+ && (ROUTE_MAP_IN_NAME(filter) || PREFIX_LIST_IN_NAME(filter)
+ || FILTER_LIST_IN_NAME(filter)
+ || DISTRIBUTE_IN_NAME(filter)))
+ return 1;
+ return 0;
+}
+
static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
safi_t safi)
{
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 97d4aaeeba..85325a93cf 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -357,6 +357,8 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t);
extern void bgp_clear_route_all(struct peer *);
extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t);
extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t);
+extern int bgp_outbound_policy_exists(struct peer *, struct bgp_filter *);
+extern int bgp_inbound_policy_exists(struct peer *, struct bgp_filter *);
extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
safi_t safi, struct prefix *p,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index a6d985ab9f..c3bd6f83b7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1860,6 +1860,29 @@ DEFUN (no_bgp_always_compare_med,
return CMD_SUCCESS;
}
+
+DEFUN(bgp_ebgp_requires_policy, bgp_ebgp_requires_policy_cmd,
+ "bgp ebgp-requires-policy",
+ "BGP specific commands\n"
+ "Require in and out policy for eBGP peers (RFC8212)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_ENABLED;
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd,
+ "no bgp ebgp-requires-policy",
+ NO_STR
+ "BGP specific commands\n"
+ "Require in and out policy for eBGP peers (RFC8212)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
+ return CMD_SUCCESS;
+}
+
+
/* "bgp deterministic-med" configuration. */
DEFUN (bgp_deterministic_med,
bgp_deterministic_med_cmd,
@@ -8829,6 +8852,20 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
json_addr, "routeMapForOutgoingAdvertisements",
filter->map[RMAP_OUT].name);
+ /* ebgp-requires-policy (inbound) */
+ if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED
+ && !bgp_inbound_policy_exists(p, filter))
+ json_object_string_add(
+ json_addr, "inboundEbgpRequiresPolicy",
+ "Inbound updates discarded due to missing policy");
+
+ /* ebgp-requires-policy (outbound) */
+ if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED
+ && (!bgp_outbound_policy_exists(p, filter)))
+ json_object_string_add(
+ json_addr, "outboundEbgpRequiresPolicy",
+ "Outbound updates discarded due to missing policy");
+
/* unsuppress-map */
if (filter->usmap.name)
json_object_string_add(json_addr,
@@ -9105,6 +9142,18 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
filter->map[RMAP_OUT].map ? "*" : "",
filter->map[RMAP_OUT].name);
+ /* ebgp-requires-policy (inbound) */
+ if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED
+ && !bgp_inbound_policy_exists(p, filter))
+ vty_out(vty,
+ " Inbound updates discarded due to missing policy\n");
+
+ /* ebgp-requires-policy (outbound) */
+ if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED
+ && !bgp_outbound_policy_exists(p, filter))
+ vty_out(vty,
+ " Outbound updates discarded due to missing policy\n");
+
/* unsuppress-map */
if (filter->usmap.name)
vty_out(vty,
@@ -12823,6 +12872,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_always_compare_med_cmd);
install_element(BGP_NODE, &no_bgp_always_compare_med_cmd);
+ /* bgp ebgp-requires-policy */
+ install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd);
+ install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd);
+
/* "bgp deterministic-med" commands */
install_element(BGP_NODE, &bgp_deterministic_med_cmd);
install_element(BGP_NODE, &no_bgp_deterministic_med_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index aceb990534..8032bf59af 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2936,6 +2936,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
bgp->dynamic_neighbors_count = 0;
+ bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
#if DFLT_BGP_IMPORT_CHECK
bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK);
#endif
@@ -7577,6 +7578,11 @@ int bgp_config_write(struct vty *vty)
if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
vty_out(vty, " bgp always-compare-med\n");
+ /* RFC8212 default eBGP policy. */
+ if (bgp->ebgp_requires_policy
+ == DEFAULT_EBGP_POLICY_ENABLED)
+ vty_out(vty, " bgp ebgp-requires-policy\n");
+
/* BGP default ipv4-unicast. */
if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4))
vty_out(vty, " no bgp default ipv4-unicast\n");
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index e58c46e240..dde1501d30 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -487,6 +487,11 @@ struct bgp {
/* EVPN enable - advertise local VNIs and their MACs etc. */
int advertise_all_vni;
+ /* RFC 8212 - prevent route leaks. */
+ int ebgp_requires_policy;
+#define DEFAULT_EBGP_POLICY_DISABLED 0
+#define DEFAULT_EBGP_POLICY_ENABLED 1
+
struct bgp_evpn_info *evpn_info;
/* EVPN - use RFC 8365 to auto-derive RT */