diff options
-rw-r--r-- | doc/bird.sgml | 9 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/bgp/config.Y | 3 | ||||
-rw-r--r-- | proto/bgp/packets.c | 40 |
4 files changed, 52 insertions, 1 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index e531da40..8d93f8ac 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2565,6 +2565,15 @@ be used in explicit configuration. <p>BGP channels have additional config options (together with the common ones): <descrip> + <tag><label id="bgp-mandatory">mandatory <m/switch/</tag> + When local and neighbor sets of configured AFI/SAFI pairs differ, + capability negotiation ensures that a common subset is used. For + mandatory channels their associated AFI/SAFI must be negotiated + (i.e., also announced by the neighbor), otherwise BGP session + negotiation fails with <it/'Required capability missing'/ error. + Regardless, at least one AFI/SAFI must be negotiated in order to BGP + session be successfully established. Default: off. + <tag><label id="bgp-next-hop-keep">next hop keep <m/switch/|ibgp|ebgp</tag> Do not modify the Next Hop attribute and advertise the current one unchanged even in cases where our own local address should be used diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 56dbf485..8c7d57b9 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -136,6 +136,7 @@ struct bgp_channel_config { ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */ u8 next_hop_self; /* Always set next hop to local IP address (NH_*) */ u8 next_hop_keep; /* Do not modify next hop attribute (NH_*) */ + u8 mandatory; /* Channel is mandatory in capability negotiation */ u8 missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */ u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */ u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index ac8d024a..9dea78ca 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -29,7 +29,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG, - LIVED, STALE, IMPORT, IBGP, EBGP) + LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY) %type <i> bgp_nh %type <i32> bgp_afi @@ -223,6 +223,7 @@ bgp_channel_item: | NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; } | NEXT HOP SELF bgp_nh { BGP_CC->next_hop_self = $4; } | NEXT HOP KEEP bgp_nh { BGP_CC->next_hop_keep = $4; } + | MANDATORY bool { BGP_CC->mandatory = $2; } | MISSING LLADDR SELF { BGP_CC->missing_lladdr = MLL_SELF; } | MISSING LLADDR DROP { BGP_CC->missing_lladdr = MLL_DROP; } | MISSING LLADDR IGNORE { BGP_CC->missing_lladdr = MLL_IGNORE; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 4ae6c5cf..c09e9859 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -574,6 +574,42 @@ err: } static int +bgp_check_capabilities(struct bgp_conn *conn) +{ + struct bgp_proto *p = conn->bgp; + struct bgp_caps *local = conn->local_caps; + struct bgp_caps *remote = conn->remote_caps; + struct bgp_channel *c; + int count = 0; + + /* This is partially overlapping with bgp_conn_enter_established_state(), + but we need to run this just after we receive OPEN message */ + + WALK_LIST(c, p->p.channels) + { + const struct bgp_af_caps *loc = bgp_find_af_caps(local, c->afi); + const struct bgp_af_caps *rem = bgp_find_af_caps(remote, c->afi); + + /* Find out whether this channel will be active */ + int active = loc && loc->ready && + ((rem && rem->ready) || (!remote->length && (c->afi == BGP_AF_IPV4))); + + /* Mandatory must be active */ + if (c->cf->mandatory && !active) + return 0; + + if (active) + count++; + } + + /* We need at least one channel active */ + if (!count) + return 0; + + return 1; +} + +static int bgp_read_options(struct bgp_conn *conn, byte *pos, int len) { struct bgp_proto *p = conn->bgp; @@ -683,6 +719,10 @@ 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 */ + if (p->cf->capabilities && !bgp_check_capabilities(conn)) + { bgp_error(conn, 2, 7, NULL, 0); return; } + struct bgp_caps *caps = conn->remote_caps; if (caps->as4_support) |