From fb29348a198d5bcb44af8057418e09c68cb438f3 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 9 Nov 2019 20:24:34 +0200 Subject: [PATCH] bgpd: Reject routes having AS_SET or AS_CONFED_SET This is the first step towards eliminating AS_SET and AS_CONFED_SET types and obsolete them in the future. More information: https://datatracker.ietf.org/doc/html/draft-ietf-idr-deprecate-as-set-confed-set-02 Signed-off-by: Donatas Abraitis --- bgpd/bgp_aspath.c | 13 +++++++++++ bgpd/bgp_aspath.h | 1 + bgpd/bgp_route.c | 59 +++++++++++++++++++++++++++++++++++++++++------ bgpd/bgp_vty.c | 54 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgpd.c | 5 ++++ bgpd/bgpd.h | 8 +++++++ 6 files changed, 133 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4257b601f1..affaaa6ac1 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -414,6 +414,19 @@ unsigned int aspath_count_hops(const struct aspath *aspath) return count; } +/* Check if aspath has AS_SET or AS_CONFED_SET */ +bool aspath_check_as_sets(struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + + while (seg) { + if (seg->type == AS_SET || seg->type == AS_CONFED_SET) + return true; + seg = seg->next; + } + return false; +} + /* Estimate size aspath /might/ take if encoded into an * ASPATH attribute. * diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 10f6ee2821..a4427714ba 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -120,6 +120,7 @@ extern int aspath_confed_check(struct aspath *); extern int aspath_left_confed_check(struct aspath *); extern unsigned long aspath_count(void); extern unsigned int aspath_count_hops(const struct aspath *); +extern bool aspath_check_as_sets(struct aspath *aspath); extern unsigned int aspath_count_confeds(struct aspath *); extern unsigned int aspath_size(struct aspath *); extern as_t aspath_highest(struct aspath *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2642266486..aaeaf963b6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1850,6 +1850,16 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, if (!bgp_outbound_policy_exists(peer, filter)) return 0; + /* draft-ietf-idr-deprecate-as-set-confed-set + * Filter routes having AS_SET or AS_CONFED_SET in the path. + * Eventually, This document (if approved) updates RFC 4271 + * and RFC 5065 by eliminating AS_SET and AS_CONFED_SET types, + * and obsoletes RFC 6472. + */ + if (peer->bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + if (aspath_check_as_sets(attr->aspath)) + return 0; + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { @@ -3143,6 +3153,19 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } + /* draft-ietf-idr-deprecate-as-set-confed-set + * Filter routes having AS_SET or AS_CONFED_SET in the path. + * Eventually, This document (if approved) updates RFC 4271 + * and RFC 5065 by eliminating AS_SET and AS_CONFED_SET types, + * and obsoletes RFC 6472. + */ + if (peer->bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + if (aspath_check_as_sets(attr->aspath)) { + reason = + "as-path contains AS_SET or AS_CONFED_SET type;"; + goto filtered; + } + bgp_attr_dup(&new_attr, attr); /* Apply incoming route-map. @@ -6363,6 +6386,7 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, /* Aggregate route attribute. */ #define AGGREGATE_SUMMARY_ONLY 1 #define AGGREGATE_AS_SET 1 +#define AGGREGATE_AS_UNSET 0 static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, afi_t afi, safi_t safi) @@ -6465,6 +6489,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, struct prefix p; struct bgp_node *rn; struct bgp_aggregate *aggregate; + uint8_t as_set_new = as_set; /* Convert string to prefix structure. */ ret = str2prefix(prefix_str, &p); @@ -6499,7 +6524,27 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, /* Make aggregate address structure. */ aggregate = bgp_aggregate_new(); aggregate->summary_only = summary_only; - aggregate->as_set = as_set; + + /* Network operators MUST NOT locally generate any new + * announcements containing AS_SET or AS_CONFED_SET. If they have + * announced routes with AS_SET or AS_CONFED_SET in them, then they + * SHOULD withdraw those routes and re-announce routes for the + * aggregate or component prefixes (i.e., the more-specific routes + * subsumed by the previously aggregated route) without AS_SET + * or AS_CONFED_SET in the updates. + */ + if (bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) { + if (as_set == AGGREGATE_AS_SET) { + as_set_new = AGGREGATE_AS_UNSET; + zlog_warn( + "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.\n", + __func__); + vty_out(vty, + "Ignoring as-set because `bgp reject-as-sets` is enabled.\n"); + } + } + + aggregate->as_set = as_set_new; aggregate->safi = safi; if (rmap) { @@ -6534,8 +6579,8 @@ DEFUN (aggregate_address, argv_find(argv, argc, "A.B.C.D/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int summary_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY @@ -6569,8 +6614,8 @@ DEFUN (aggregate_address_mask, char *mask = argv[idx + 1]->arg; bool rmap_found; char *rmap = NULL; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int summary_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY @@ -6658,8 +6703,8 @@ DEFUN (ipv6_aggregate_address, char *prefix = argv[idx]->arg; char *rmap = NULL; bool rmap_found; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int sum_only = argv_find(argv, argc, "summary-only", &idx) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 17c93ffc38..0c3e15f0df 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1921,6 +1921,56 @@ DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, return CMD_SUCCESS; } +DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, + "bgp reject-as-sets", + "BGP specific commands\n" + "Reject routes with AS_SET or AS_CONFED_SET flag\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; + + bgp->reject_as_sets = BGP_REJECT_AS_SETS_ENABLED; + + /* Reset existing BGP sessions to reject routes + * with aspath containing AS_SET or AS_CONFED_SET. + */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + + return CMD_SUCCESS; +} + +DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, + "no bgp reject-as-sets", + NO_STR + "BGP specific commands\n" + "Reject routes with AS_SET or AS_CONFED_SET flag\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; + + bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; + + /* Reset existing BGP sessions to reject routes + * with aspath containing AS_SET or AS_CONFED_SET. + */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + + return CMD_SUCCESS; +} /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, @@ -13128,6 +13178,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* bgp reject-as-sets */ + install_element(BGP_NODE, &bgp_reject_as_sets_cmd); + install_element(BGP_NODE, &no_bgp_reject_as_sets_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 7621d7ef0f..806d686b47 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2966,6 +2966,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; + bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; #if DFLT_BGP_IMPORT_CHECK bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); #endif @@ -7588,6 +7589,10 @@ int bgp_config_write(struct vty *vty) == DEFAULT_EBGP_POLICY_ENABLED) vty_out(vty, " bgp ebgp-requires-policy\n"); + /* draft-ietf-idr-deprecate-as-set-confed-set */ + if (bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + vty_out(vty, " bgp reject-as-sets\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 317f200b85..ce7f845ca5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -504,6 +504,13 @@ struct bgp { #define DEFAULT_EBGP_POLICY_DISABLED 0 #define DEFAULT_EBGP_POLICY_ENABLED 1 + /* draft-ietf-idr-deprecate-as-set-confed-set + * Reject aspaths with AS_SET and/or AS_CONFED_SET. + */ + bool reject_as_sets; +#define BGP_REJECT_AS_SETS_DISABLED 0 +#define BGP_REJECT_AS_SETS_ENABLED 1 + struct bgp_evpn_info *evpn_info; /* EVPN - use RFC 8365 to auto-derive RT */ @@ -1203,6 +1210,7 @@ struct peer { #define PEER_DOWN_NBR_ADDR 28 /* Waiting for peer IPv6 IP Addr */ #define PEER_DOWN_VRF_UNINIT 29 /* Associated VRF is not init yet */ #define PEER_DOWN_NOAFI_ACTIVATED 30 /* No AFI/SAFI activated for peer */ +#define PEER_DOWN_AS_SETS_REJECT 31 /* Reject routes with AS_SET */ size_t last_reset_cause_size; uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE]; -- 2.39.5