From 5e81120961d502a25da5a590011ed6dda86024b7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 6 Oct 2023 14:51:18 +0300 Subject: [PATCH] bgpd: Implement EBGP-OAD peering type At each EBGP boundary, BGP path attributes are modified as per [RFC4271], which includes stripping any IBGP-only attributes. Some networks span more than one autonomous system and require more flexibility in the propagation of path attributes. It is worth noting that these multi-AS networks have a common or single administrative entity. These networks are said to belong to One Administrative Domain (OAD). It is desirable to carry IBGP-only attributes across EBGP peerings when the peers belong to an OAD. This document defines a new EBGP peering type known as EBGP-OAD, which is used between two EBGP peers that belong to an OAD. This document also defines rules for route announcement and processing for EBGP-OAD peers. https://datatracker.ietf.org/doc/html/draft-uttaro-idr-bgp-oad Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 13 +++++++++---- bgpd/bgp_route.c | 9 +++++---- bgpd/bgp_updgrp.c | 1 + bgpd/bgp_vty.c | 28 ++++++++++++++++++++++++++++ bgpd/bgpd.c | 1 + bgpd/bgpd.h | 9 +++++++++ 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 808b98e419..21736dfb83 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1952,7 +1952,9 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) * UPDATE message SHALL be handled using the approach of "treat-as- * withdraw". */ - if (peer->sort == BGP_PEER_IBGP && length != 4) { + if ((peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) && + length != 4) { flog_err(EC_BGP_ATTR_LEN, "LOCAL_PREF attribute length isn't 4 [%u]", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -1962,7 +1964,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ - if (peer->sort == BGP_PEER_EBGP) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) { STREAM_FORWARD_GETP(peer->curr, length); return BGP_ATTR_PARSE_PROCEED; } @@ -3380,7 +3382,8 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args) * the default value of AIGP_SESSION SHOULD be "enabled". */ if (peer->sort == BGP_PEER_EBGP && - !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) { + (!CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort != BGP_PEER_EBGP_OAD)) { zlog_warn( "%pBP received AIGP attribute, but eBGP peer do not support it", peer); @@ -4639,7 +4642,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* Local preference. */ - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LOCAL_PREF); stream_putc(s, 4); @@ -5013,6 +5017,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* AIGP */ if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort == BGP_PEER_EBGP_OAD || peer->sort != BGP_PEER_EBGP)) { /* At the moment only AIGP Metric TLV exists for AIGP * attribute. If more comes in, do not forget to update diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 71b43c6756..6cc27b98d4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2300,8 +2300,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ - if (peer->sort == BGP_PEER_EBGP - && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && + attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { if (from != bgp->peer_self && !transparent && !CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) @@ -2515,8 +2515,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, return false; if (bgp_in_graceful_shutdown(bgp)) { - if (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || + peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); attr->local_pref = BGP_GSHUT_LOCAL_PREF; } else { diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a2006c3508..9eb4433c55 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -128,6 +128,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->bgp = src->bgp; dst->sort = src->sort; + dst->sub_sort = src->sub_sort; dst->as = src->as; dst->v_routeadv = src->v_routeadv; dst->flags = src->flags; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9b4d893682..6bb42c8917 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6985,6 +6985,28 @@ DEFPY(no_neighbor_role, return ret; } +DEFPY (neighbor_oad, + neighbor_oad_cmd, + "[no$no] neighbor $neighbor oad", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set peering session type to EBGP-OAD\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + peer->sub_sort = 0; + else if (peer->sort == BGP_PEER_EBGP) + peer->sub_sort = BGP_PEER_EBGP_OAD; + + return CMD_SUCCESS; +} + /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, @@ -17971,6 +17993,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, ? " strict-mode" : ""); + if (peer->sub_sort == BGP_PEER_EBGP_OAD) + vty_out(vty, " neighbor %s oad\n", addr); + /* ttl-security hops */ if (peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) { if (!peer_group_active(peer) @@ -19557,6 +19582,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_role_strict_cmd); install_element(BGP_NODE, &no_neighbor_role_cmd); + /* "neighbor oad" commands. */ + install_element(BGP_NODE, &neighbor_oad_cmd); + /* "neighbor aigp" commands. */ install_element(BGP_NODE, &neighbor_aigp_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e760d41587..894ebaa84f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3153,6 +3153,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->as_type = group->conf->as_type; peer->as = group->conf->as; peer->sort = group->conf->sort; + peer->sub_sort = group->conf->sub_sort; } ptype = peer_sort(peer); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8f78e33f65..d324381080 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -973,6 +973,14 @@ enum bgp_peer_sort { BGP_PEER_CONFED, }; +/* BGP peering sub-types + * E.g.: + * EBGP-OAD - https://datatracker.ietf.org/doc/html/draft-uttaro-idr-bgp-oad + */ +enum bgp_peer_sub_sort { + BGP_PEER_EBGP_OAD = 1, +}; + /* BGP message header and packet size. */ #define BGP_MARKER_SIZE 16 #define BGP_HEADER_SIZE 19 @@ -1199,6 +1207,7 @@ struct peer { as_t local_as; enum bgp_peer_sort sort; + enum bgp_peer_sub_sort sub_sort; /* Peer's Change local AS number. */ as_t change_local_as; -- 2.39.5