Merge branch 'master' into backport
This commit is contained in:
commit
2e484f8d29
6 changed files with 195 additions and 6 deletions
|
@ -2377,6 +2377,7 @@ avoid routing loops.
|
||||||
<item> <rfc id="8203"> - BGP Administrative Shutdown Communication
|
<item> <rfc id="8203"> - BGP Administrative Shutdown Communication
|
||||||
<item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
|
<item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
|
||||||
<item> <rfc id="9117"> - Revised Validation Procedure for BGP Flow Specifications
|
<item> <rfc id="9117"> - Revised Validation Procedure for BGP Flow Specifications
|
||||||
|
<item> <rfc id="9234"> - Route Leak Prevention and Detection Using Roles
|
||||||
</itemize>
|
</itemize>
|
||||||
|
|
||||||
<sect1>Route selection rules
|
<sect1>Route selection rules
|
||||||
|
@ -2817,6 +2818,29 @@ using the following configuration parameters:
|
||||||
protocol itself (for example, if a route is received through eBGP and
|
protocol itself (for example, if a route is received through eBGP and
|
||||||
therefore does not have such attribute). Default: 100 (0 in pre-1.2.0
|
therefore does not have such attribute). Default: 100 (0 in pre-1.2.0
|
||||||
versions of BIRD).
|
versions of BIRD).
|
||||||
|
|
||||||
|
<tag><label id="bgp-local-role">local role <m/role-name/</tag>
|
||||||
|
BGP roles are a mechanism for route leak prevention and automatic route
|
||||||
|
filtering based on common BGP topology relationships. They are defined
|
||||||
|
in <rfc id="9234">. Instead of manually configuring filters and
|
||||||
|
communities, automatic filtering is done with the help of the OTC
|
||||||
|
attribute - a flag for routes that should be sent only to customers.
|
||||||
|
The same attribute is also used to automatically detect and filter route
|
||||||
|
leaks created by third parties.
|
||||||
|
|
||||||
|
This option is valid for EBGP sessions, but it is not recommended to be
|
||||||
|
used within AS confederations (which would require manual filtering of
|
||||||
|
<cf/bgp_otc/ attribute on confederation boundaries).
|
||||||
|
|
||||||
|
Possible <cf><m/role-name/</cf> values are: <cf/provider/,
|
||||||
|
<cf/rs_server/, <cf/rs_client/, <cf/customer/ and <cf/peer/.
|
||||||
|
Default: No local role assigned.
|
||||||
|
|
||||||
|
<tag><label id="bgp-require-roles">require roles <m/switch/</tag>
|
||||||
|
If this option is set, the BGP roles must be defined on both sides,
|
||||||
|
otherwise the session will not be established. This behavior is defined
|
||||||
|
in <rfc id="9234"> as "strict mode" and is used to enforce corresponding
|
||||||
|
configuration at your conterpart side. Default: disabled.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<sect1>Channel configuration
|
<sect1>Channel configuration
|
||||||
|
@ -3124,6 +3148,11 @@ some of them (marked with `<tt/O/') are optional.
|
||||||
This attribute contains accumulated IGP metric, which is a total
|
This attribute contains accumulated IGP metric, which is a total
|
||||||
distance to the destination through multiple autonomous systems.
|
distance to the destination through multiple autonomous systems.
|
||||||
Currently, the attribute is not accessible from filters.
|
Currently, the attribute is not accessible from filters.
|
||||||
|
|
||||||
|
<tag><label id="bgp-otc">int bgp_otc [O]</tag>
|
||||||
|
This attribute is defined in <rfc id="9234">. OTC is a flag that marks
|
||||||
|
routes that should be sent only to customers. If <ref id="bgp-role"
|
||||||
|
name="local Role"> is configured it set automatically.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<sect1>Example
|
<sect1>Example
|
||||||
|
|
|
@ -903,6 +903,18 @@ bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint fla
|
||||||
bgp_set_attr_ptr(to, s->pool, BA_LARGE_COMMUNITY, flags, ad);
|
bgp_set_attr_ptr(to, s->pool, BA_LARGE_COMMUNITY, flags, ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_decode_otc(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data UNUSED, uint len, ea_list **to)
|
||||||
|
{
|
||||||
|
if (len != 4)
|
||||||
|
WITHDRAW(BAD_LENGTH, "OTC", len);
|
||||||
|
|
||||||
|
u32 val = get_u32(data);
|
||||||
|
bgp_set_attr_u32(to, s->pool, BA_ONLY_TO_CUSTOMER, flags, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
|
bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
|
||||||
{
|
{
|
||||||
|
@ -1116,6 +1128,13 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
|
||||||
.encode = bgp_encode_u32s,
|
.encode = bgp_encode_u32s,
|
||||||
.decode = bgp_decode_large_community,
|
.decode = bgp_decode_large_community,
|
||||||
},
|
},
|
||||||
|
[BA_ONLY_TO_CUSTOMER] = {
|
||||||
|
.name = "otc",
|
||||||
|
.type = EAF_TYPE_INT,
|
||||||
|
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
|
||||||
|
.encode = bgp_encode_u32,
|
||||||
|
.decode = bgp_decode_otc,
|
||||||
|
},
|
||||||
[BA_MPLS_LABEL_STACK] = {
|
[BA_MPLS_LABEL_STACK] = {
|
||||||
.name = "mpls_label_stack",
|
.name = "mpls_label_stack",
|
||||||
.type = EAF_TYPE_INT_SET,
|
.type = EAF_TYPE_INT_SET,
|
||||||
|
@ -1452,6 +1471,29 @@ bgp_finish_attrs(struct bgp_parse_state *s, rta *a)
|
||||||
REPORT("Discarding AIGP attribute received on non-AIGP session");
|
REPORT("Discarding AIGP attribute received on non-AIGP session");
|
||||||
bgp_unset_attr(&a->eattrs, s->pool, BA_AIGP);
|
bgp_unset_attr(&a->eattrs, s->pool, BA_AIGP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle OTC ingress procedure, RFC 9234 */
|
||||||
|
if (bgp_channel_is_role_applicable(s->channel))
|
||||||
|
{
|
||||||
|
struct bgp_proto *p = s->proto;
|
||||||
|
eattr *e = bgp_find_attr(a->eattrs, BA_ONLY_TO_CUSTOMER);
|
||||||
|
|
||||||
|
/* Reject routes from downstream if they are leaked */
|
||||||
|
if (e && (p->cf->local_role == BGP_ROLE_PROVIDER ||
|
||||||
|
p->cf->local_role == BGP_ROLE_RS_SERVER))
|
||||||
|
WITHDRAW("Route leak detected - OTC attribute from downstream");
|
||||||
|
|
||||||
|
/* Reject routes from peers if they are leaked */
|
||||||
|
if (e && (p->cf->local_role == BGP_ROLE_PEER) && (e->u.data != p->cf->remote_as))
|
||||||
|
WITHDRAW("Route leak detected - OTC attribute with mismatched ASN (%u)",
|
||||||
|
(uint) e->u.data);
|
||||||
|
|
||||||
|
/* Mark routes from upstream if it did not happened before */
|
||||||
|
if (!e && (p->cf->local_role == BGP_ROLE_CUSTOMER ||
|
||||||
|
p->cf->local_role == BGP_ROLE_PEER ||
|
||||||
|
p->cf->local_role == BGP_ROLE_RS_CLIENT))
|
||||||
|
bgp_set_attr_u32(&a->eattrs, s->pool, BA_ONLY_TO_CUSTOMER, 0, p->cf->remote_as);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1681,6 +1723,7 @@ bgp_preexport(struct channel *C, rte *e)
|
||||||
struct proto *SRC = e->src->proto;
|
struct proto *SRC = e->src->proto;
|
||||||
struct bgp_proto *p = (struct bgp_proto *) C->proto;
|
struct bgp_proto *p = (struct bgp_proto *) C->proto;
|
||||||
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
|
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
|
||||||
|
struct bgp_channel *c = (struct bgp_channel *) C;
|
||||||
|
|
||||||
/* Reject our routes */
|
/* Reject our routes */
|
||||||
if (src == p)
|
if (src == p)
|
||||||
|
@ -1708,11 +1751,11 @@ bgp_preexport(struct channel *C, rte *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle well-known communities, RFC 1997 */
|
/* Handle well-known communities, RFC 1997 */
|
||||||
struct eattr *c;
|
struct eattr *a;
|
||||||
if (p->cf->interpret_communities &&
|
if (p->cf->interpret_communities &&
|
||||||
(c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
|
(a = bgp_find_attr(e->attrs->eattrs, BA_COMMUNITY)))
|
||||||
{
|
{
|
||||||
const struct adata *d = c->u.ptr;
|
const struct adata *d = a->u.ptr;
|
||||||
|
|
||||||
/* Do not export anywhere */
|
/* Do not export anywhere */
|
||||||
if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
|
if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
|
||||||
|
@ -1731,6 +1774,16 @@ bgp_preexport(struct channel *C, rte *e)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do not export routes marked with OTC to upstream, RFC 9234 */
|
||||||
|
if (bgp_channel_is_role_applicable(c))
|
||||||
|
{
|
||||||
|
a = bgp_find_attr(e->attrs->eattrs, BA_ONLY_TO_CUSTOMER);
|
||||||
|
if (a && (p->cf->local_role==BGP_ROLE_CUSTOMER ||
|
||||||
|
p->cf->local_role==BGP_ROLE_PEER ||
|
||||||
|
p->cf->local_role==BGP_ROLE_RS_CLIENT))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1840,6 +1893,16 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark routes for downstream with OTC, RFC 9234 */
|
||||||
|
if (bgp_channel_is_role_applicable(c))
|
||||||
|
{
|
||||||
|
a = bgp_find_attr(attrs, BA_ONLY_TO_CUSTOMER);
|
||||||
|
if (!a && (p->cf->local_role == BGP_ROLE_PROVIDER ||
|
||||||
|
p->cf->local_role == BGP_ROLE_PEER ||
|
||||||
|
p->cf->local_role == BGP_ROLE_RS_SERVER))
|
||||||
|
bgp_set_attr_u32(&attrs, pool, BA_ONLY_TO_CUSTOMER, 0, p->public_as);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
|
* Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
|
||||||
* conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
|
* conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
|
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
|
||||||
* RFC 8654 - Extended Message Support for BGP
|
* RFC 8654 - Extended Message Support for BGP
|
||||||
* RFC 9117 - Revised Validation Procedure for BGP Flow Specifications
|
* RFC 9117 - Revised Validation Procedure for BGP Flow Specifications
|
||||||
|
* RFC 9234 - Route Leak Prevention and Detection Using Roles
|
||||||
* draft-ietf-idr-ext-opt-param-07
|
* draft-ietf-idr-ext-opt-param-07
|
||||||
* draft-uttaro-idr-bgp-persistence-04
|
* draft-uttaro-idr-bgp-persistence-04
|
||||||
* draft-walton-bgp-hostname-capability-02
|
* draft-walton-bgp-hostname-capability-02
|
||||||
|
@ -1963,6 +1964,15 @@ bgp_postconfig(struct proto_config *CF)
|
||||||
if (internal && cf->rs_client)
|
if (internal && cf->rs_client)
|
||||||
cf_error("Only external neighbor can be RS client");
|
cf_error("Only external neighbor can be RS client");
|
||||||
|
|
||||||
|
if (internal && (cf->local_role != BGP_ROLE_UNDEFINED))
|
||||||
|
cf_error("Local role cannot be set on IBGP sessions");
|
||||||
|
|
||||||
|
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_roles && (cf->local_role == BGP_ROLE_UNDEFINED))
|
||||||
|
cf_error("Local role must be set if roles are required");
|
||||||
|
|
||||||
if (!cf->confederation && cf->confederation_member)
|
if (!cf->confederation && cf->confederation_member)
|
||||||
cf_error("Confederation ID must be set for member sessions");
|
cf_error("Confederation ID must be set for member sessions");
|
||||||
|
|
||||||
|
@ -2325,6 +2335,15 @@ bgp_show_afis(int code, char *s, u32 *afis, uint count)
|
||||||
cli_msg(code, b.start);
|
cli_msg(code, b.start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
bgp_format_role_name(u8 role)
|
||||||
|
{
|
||||||
|
static const char *bgp_role_names[] = { "provider", "rs_server", "rs_client", "customer", "peer" };
|
||||||
|
if (role == BGP_ROLE_UNDEFINED) return "undefined";
|
||||||
|
if (role < ARRAY_SIZE(bgp_role_names)) return bgp_role_names[role];
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
|
bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
|
||||||
{
|
{
|
||||||
|
@ -2453,6 +2472,9 @@ bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
|
||||||
|
|
||||||
if (caps->hostname)
|
if (caps->hostname)
|
||||||
cli_msg(-1006, " Hostname: %s", caps->hostname);
|
cli_msg(-1006, " Hostname: %s", caps->hostname);
|
||||||
|
|
||||||
|
if (caps->role != BGP_ROLE_UNDEFINED)
|
||||||
|
cli_msg(-1006, " Role: %s", bgp_format_role_name(caps->role));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -113,6 +113,8 @@ struct bgp_config {
|
||||||
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
|
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
|
||||||
int llgr_mode; /* Long-lived graceful restart mode (BGP_LLGR_*) */
|
int llgr_mode; /* Long-lived graceful restart mode (BGP_LLGR_*) */
|
||||||
int setkey; /* Set MD5 password to system SA/SP database */
|
int setkey; /* Set MD5 password to system SA/SP database */
|
||||||
|
u8 local_role; /* Set peering role with neighbor [RFC 9234] */
|
||||||
|
int require_roles; /* Require configured roles on both sides */
|
||||||
/* Times below are in seconds */
|
/* Times below are in seconds */
|
||||||
unsigned gr_time; /* Graceful restart timeout */
|
unsigned gr_time; /* Graceful restart timeout */
|
||||||
unsigned llgr_time; /* Long-lived graceful restart stale time */
|
unsigned llgr_time; /* Long-lived graceful restart stale time */
|
||||||
|
@ -166,6 +168,13 @@ struct bgp_channel_config {
|
||||||
#define BGP_PT_INTERNAL 1
|
#define BGP_PT_INTERNAL 1
|
||||||
#define BGP_PT_EXTERNAL 2
|
#define BGP_PT_EXTERNAL 2
|
||||||
|
|
||||||
|
#define BGP_ROLE_UNDEFINED 255
|
||||||
|
#define BGP_ROLE_PROVIDER 0
|
||||||
|
#define BGP_ROLE_RS_SERVER 1
|
||||||
|
#define BGP_ROLE_RS_CLIENT 2
|
||||||
|
#define BGP_ROLE_CUSTOMER 3
|
||||||
|
#define BGP_ROLE_PEER 4
|
||||||
|
|
||||||
#define NH_NO 0
|
#define NH_NO 0
|
||||||
#define NH_ALL 1
|
#define NH_ALL 1
|
||||||
#define NH_IBGP 2
|
#define NH_IBGP 2
|
||||||
|
@ -226,6 +235,7 @@ struct bgp_caps {
|
||||||
u8 ext_messages; /* Extended message length, RFC draft */
|
u8 ext_messages; /* Extended message length, RFC draft */
|
||||||
u8 route_refresh; /* Route refresh capability, RFC 2918 */
|
u8 route_refresh; /* Route refresh capability, RFC 2918 */
|
||||||
u8 enhanced_refresh; /* Enhanced route refresh, RFC 7313 */
|
u8 enhanced_refresh; /* Enhanced route refresh, RFC 7313 */
|
||||||
|
u8 role; /* BGP role capability, RFC 9234 */
|
||||||
|
|
||||||
u8 gr_aware; /* Graceful restart capability, RFC 4724 */
|
u8 gr_aware; /* Graceful restart capability, RFC 4724 */
|
||||||
u8 gr_flags; /* Graceful restart flags */
|
u8 gr_flags; /* Graceful restart flags */
|
||||||
|
@ -487,6 +497,12 @@ static inline int bgp_cc_is_ipv4(struct bgp_channel_config *c)
|
||||||
static inline int bgp_cc_is_ipv6(struct bgp_channel_config *c)
|
static inline int bgp_cc_is_ipv6(struct bgp_channel_config *c)
|
||||||
{ return BGP_AFI(c->afi) == BGP_AFI_IPV6; }
|
{ return BGP_AFI(c->afi) == BGP_AFI_IPV6; }
|
||||||
|
|
||||||
|
static inline int bgp_channel_is_role_applicable(struct bgp_channel *c)
|
||||||
|
{ return (c->afi == BGP_AF_IPV4 || c->afi == BGP_AF_IPV6); }
|
||||||
|
|
||||||
|
static inline int bgp_cc_is_role_applicable(struct bgp_channel_config *c)
|
||||||
|
{ return (c->afi == BGP_AF_IPV4 || c->afi == BGP_AF_IPV6); }
|
||||||
|
|
||||||
static inline uint bgp_max_packet_length(struct bgp_conn *conn)
|
static inline uint bgp_max_packet_length(struct bgp_conn *conn)
|
||||||
{ return conn->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; }
|
{ return conn->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; }
|
||||||
|
|
||||||
|
@ -658,6 +674,7 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to);
|
||||||
#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */
|
#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */
|
||||||
#define BA_AIGP 0x1a /* RFC 7311 */
|
#define BA_AIGP 0x1a /* RFC 7311 */
|
||||||
#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */
|
#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */
|
||||||
|
#define BA_ONLY_TO_CUSTOMER 0x23 /* RFC 9234 */
|
||||||
|
|
||||||
/* Bird's private internal BGP attributes */
|
/* Bird's private internal BGP attributes */
|
||||||
#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */
|
#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */
|
||||||
|
|
|
@ -31,7 +31,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
||||||
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
|
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
|
||||||
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
|
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
|
||||||
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
|
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
|
||||||
FIRST, FREE, VALIDATE, BASE)
|
FIRST, FREE, VALIDATE, BASE, ROLE, ROLES, PEER, PROVIDER, CUSTOMER,
|
||||||
|
RS_SERVER, RS_CLIENT, REQUIRE, BGP_OTC)
|
||||||
|
|
||||||
%type <i> bgp_nh
|
%type <i> bgp_nh
|
||||||
%type <i32> bgp_afi
|
%type <i32> bgp_afi
|
||||||
|
@ -40,7 +41,7 @@ CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
|
||||||
CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
|
CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
|
||||||
OUT, OF, RESOURCES)
|
OUT, OF, RESOURCES)
|
||||||
|
|
||||||
%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag
|
%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag bgp_role_name
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -72,6 +73,7 @@ bgp_proto_start: proto_start BGP {
|
||||||
BGP_CFG->llgr_mode = -1;
|
BGP_CFG->llgr_mode = -1;
|
||||||
BGP_CFG->llgr_time = 3600;
|
BGP_CFG->llgr_time = 3600;
|
||||||
BGP_CFG->setkey = 1;
|
BGP_CFG->setkey = 1;
|
||||||
|
BGP_CFG->local_role = BGP_ROLE_UNDEFINED;
|
||||||
BGP_CFG->dynamic_name = "dynbgp";
|
BGP_CFG->dynamic_name = "dynbgp";
|
||||||
BGP_CFG->check_link = -1;
|
BGP_CFG->check_link = -1;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +116,14 @@ bgp_cease_flag:
|
||||||
| OUT OF RESOURCES { $$ = 1 << 8; }
|
| OUT OF RESOURCES { $$ = 1 << 8; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
bgp_role_name:
|
||||||
|
PEER { $$ = BGP_ROLE_PEER; }
|
||||||
|
| PROVIDER { $$ = BGP_ROLE_PROVIDER; }
|
||||||
|
| CUSTOMER { $$ = BGP_ROLE_CUSTOMER; }
|
||||||
|
| RS_SERVER { $$ = BGP_ROLE_RS_SERVER; }
|
||||||
|
| RS_CLIENT { $$ = BGP_ROLE_RS_CLIENT; }
|
||||||
|
;
|
||||||
|
|
||||||
bgp_proto:
|
bgp_proto:
|
||||||
bgp_proto_start proto_name '{'
|
bgp_proto_start proto_name '{'
|
||||||
| bgp_proto proto_item ';'
|
| bgp_proto proto_item ';'
|
||||||
|
@ -197,6 +207,8 @@ bgp_proto:
|
||||||
| bgp_proto BFD GRACEFUL ';' { init_bfd_opts(&BGP_CFG->bfd); BGP_CFG->bfd->mode = BGP_BFD_GRACEFUL; }
|
| bgp_proto BFD GRACEFUL ';' { init_bfd_opts(&BGP_CFG->bfd); BGP_CFG->bfd->mode = BGP_BFD_GRACEFUL; }
|
||||||
| bgp_proto BFD { open_bfd_opts(&BGP_CFG->bfd); } bfd_opts { close_bfd_opts(); } ';'
|
| bgp_proto BFD { open_bfd_opts(&BGP_CFG->bfd); } bfd_opts { close_bfd_opts(); } ';'
|
||||||
| bgp_proto ENFORCE FIRST AS bool ';' { BGP_CFG->enforce_first_as = $5; }
|
| bgp_proto ENFORCE FIRST AS bool ';' { BGP_CFG->enforce_first_as = $5; }
|
||||||
|
| bgp_proto LOCAL ROLE bgp_role_name ';' { BGP_CFG->local_role = $4; }
|
||||||
|
| bgp_proto REQUIRE ROLES bool ';' { BGP_CFG->require_roles = $4; }
|
||||||
;
|
;
|
||||||
|
|
||||||
bgp_afi:
|
bgp_afi:
|
||||||
|
@ -343,6 +355,8 @@ dynamic_attr: BGP_AIGP
|
||||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ;
|
{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ;
|
||||||
dynamic_attr: BGP_LARGE_COMMUNITY
|
dynamic_attr: BGP_LARGE_COMMUNITY
|
||||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
|
{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
|
||||||
|
dynamic_attr: BGP_OTC
|
||||||
|
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_ONLY_TO_CUSTOMER)); } ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,7 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
|
||||||
caps->ext_messages = p->cf->enable_extended_messages;
|
caps->ext_messages = p->cf->enable_extended_messages;
|
||||||
caps->route_refresh = p->cf->enable_refresh;
|
caps->route_refresh = p->cf->enable_refresh;
|
||||||
caps->enhanced_refresh = p->cf->enable_refresh;
|
caps->enhanced_refresh = p->cf->enable_refresh;
|
||||||
|
caps->role = p->cf->local_role;
|
||||||
|
|
||||||
if (caps->as4_support)
|
if (caps->as4_support)
|
||||||
caps->as4_number = p->public_as;
|
caps->as4_number = p->public_as;
|
||||||
|
@ -350,6 +351,13 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
*buf++ = 0; /* Capability data length */
|
*buf++ = 0; /* Capability data length */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (caps->role != BGP_ROLE_UNDEFINED)
|
||||||
|
{
|
||||||
|
*buf++ = 9; /* Capability 9: Announce chosen BGP role */
|
||||||
|
*buf++ = 1; /* Capability data length */
|
||||||
|
*buf++ = caps->role;
|
||||||
|
}
|
||||||
|
|
||||||
if (caps->gr_aware)
|
if (caps->gr_aware)
|
||||||
{
|
{
|
||||||
*buf++ = 64; /* Capability 64: Support for graceful restart */
|
*buf++ = 64; /* Capability 64: Support for graceful restart */
|
||||||
|
@ -449,11 +457,15 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||||
struct bgp_proto *p = conn->bgp;
|
struct bgp_proto *p = conn->bgp;
|
||||||
struct bgp_caps *caps;
|
struct bgp_caps *caps;
|
||||||
struct bgp_af_caps *ac;
|
struct bgp_af_caps *ac;
|
||||||
|
uint err_subcode = 0;
|
||||||
int i, cl;
|
int i, cl;
|
||||||
u32 af;
|
u32 af;
|
||||||
|
|
||||||
if (!conn->remote_caps)
|
if (!conn->remote_caps)
|
||||||
|
{
|
||||||
caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + sizeof(struct bgp_af_caps));
|
caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + sizeof(struct bgp_af_caps));
|
||||||
|
caps->role = BGP_ROLE_UNDEFINED;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
caps = conn->remote_caps;
|
caps = conn->remote_caps;
|
||||||
|
@ -513,6 +525,21 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||||
caps->ext_messages = 1;
|
caps->ext_messages = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 9: /* BGP role capability, RFC 9234 */
|
||||||
|
if (cl != 1)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Reserved value */
|
||||||
|
if (pos[2] == BGP_ROLE_UNDEFINED)
|
||||||
|
{ err_subcode = 11; goto err; }
|
||||||
|
|
||||||
|
/* Multiple inconsistent values */
|
||||||
|
if ((caps->role != BGP_ROLE_UNDEFINED) && (caps->role != pos[2]))
|
||||||
|
{ err_subcode = 11; goto err; }
|
||||||
|
|
||||||
|
caps->role = pos[2];
|
||||||
|
break;
|
||||||
|
|
||||||
case 64: /* Graceful restart capability, RFC 4724 */
|
case 64: /* Graceful restart capability, RFC 4724 */
|
||||||
if (cl % 4 != 2)
|
if (cl % 4 != 2)
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -638,7 +665,7 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||||
|
|
||||||
err:
|
err:
|
||||||
mb_free(caps);
|
mb_free(caps);
|
||||||
bgp_error(conn, 2, 0, NULL, 0);
|
bgp_error(conn, 2, err_subcode, NULL, 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,6 +881,22 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
conn->received_as = asn;
|
conn->received_as = asn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RFC 9234 4.2 - check role agreement */
|
||||||
|
u8 local_role = p->cf->local_role;
|
||||||
|
u8 neigh_role = caps->role;
|
||||||
|
|
||||||
|
if ((local_role != BGP_ROLE_UNDEFINED) &&
|
||||||
|
(neigh_role != BGP_ROLE_UNDEFINED) &&
|
||||||
|
!((local_role == BGP_ROLE_PEER && neigh_role == BGP_ROLE_PEER) ||
|
||||||
|
(local_role == BGP_ROLE_CUSTOMER && neigh_role == BGP_ROLE_PROVIDER) ||
|
||||||
|
(local_role == BGP_ROLE_PROVIDER && neigh_role == BGP_ROLE_CUSTOMER) ||
|
||||||
|
(local_role == BGP_ROLE_RS_CLIENT && neigh_role == BGP_ROLE_RS_SERVER) ||
|
||||||
|
(local_role == BGP_ROLE_RS_SERVER && neigh_role == BGP_ROLE_RS_CLIENT)))
|
||||||
|
{ bgp_error(conn, 2, 11, NULL, 0); return; }
|
||||||
|
|
||||||
|
if ((p->cf->require_roles) && (neigh_role == BGP_ROLE_UNDEFINED))
|
||||||
|
{ bgp_error(conn, 2, 11, NULL, 0); return; }
|
||||||
|
|
||||||
/* Check the other connection */
|
/* Check the other connection */
|
||||||
other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
|
other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
|
||||||
switch (other->state)
|
switch (other->state)
|
||||||
|
@ -2985,6 +3028,7 @@ static struct {
|
||||||
{ 2, 6, "Unacceptable hold time" },
|
{ 2, 6, "Unacceptable hold time" },
|
||||||
{ 2, 7, "Required capability missing" }, /* [RFC5492] */
|
{ 2, 7, "Required capability missing" }, /* [RFC5492] */
|
||||||
{ 2, 8, "No supported AFI/SAFI" }, /* This error msg is nonstandard */
|
{ 2, 8, "No supported AFI/SAFI" }, /* This error msg is nonstandard */
|
||||||
|
{ 2,11, "Role mismatch" }, /* From Open Policy, RFC 9234 */
|
||||||
{ 3, 0, "Invalid UPDATE message" },
|
{ 3, 0, "Invalid UPDATE message" },
|
||||||
{ 3, 1, "Malformed attribute list" },
|
{ 3, 1, "Malformed attribute list" },
|
||||||
{ 3, 2, "Unrecognized well-known attribute" },
|
{ 3, 2, "Unrecognized well-known attribute" },
|
||||||
|
|
Loading…
Reference in a new issue