diff options
Diffstat (limited to 'bgpd/bgp_open.c')
| -rw-r--r-- | bgpd/bgp_open.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index fa3fa3fcee..d8dd71788b 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -58,6 +58,7 @@ static const struct message capcode_str[] = { {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, {CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"}, + {CAPABILITY_CODE_ROLE, "Role"}, {0}}; /* Minimum sizes for length field of each cap (so not inc. the header) */ @@ -77,6 +78,7 @@ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, + [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, }; /* value the capability must be a multiple of. @@ -100,6 +102,7 @@ static const size_t cap_modsizes[] = { [CAPABILITY_CODE_ENHANCED_RR] = 1, [CAPABILITY_CODE_EXT_MESSAGE] = 1, [CAPABILITY_CODE_LLGR] = 1, + [CAPABILITY_CODE_ROLE] = 1, }; /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -887,6 +890,20 @@ static int bgp_capability_hostname(struct peer *peer, return 0; } +static int bgp_capability_role(struct peer *peer, struct capability_header *hdr) +{ + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Role: Received invalid length %d", hdr->length); + return -1; + } + uint8_t role = stream_getc(BGP_INPUT(peer)); + + peer->neighbor_role = role; + return 0; +} + /** * Parse given capability. * XXX: This is reading into a stream, but not using stream API @@ -954,6 +971,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHANCED_RR: case CAPABILITY_CODE_EXT_MESSAGE: + case CAPABILITY_CODE_ROLE: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -1051,6 +1069,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_FQDN: ret = bgp_capability_hostname(peer, &caphdr); break; + case CAPABILITY_CODE_ROLE: + ret = bgp_capability_role(peer, &caphdr); + break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor @@ -1113,6 +1134,35 @@ static bool strict_capability_same(struct peer *peer) return true; } + +static bool bgp_role_violation(struct peer *peer) +{ + uint8_t local_role = peer->local_role; + uint8_t neigh_role = peer->neighbor_role; + + if (local_role != ROLE_UNDEFINE && neigh_role != ROLE_UNDEFINE && + !((local_role == ROLE_PEER && neigh_role == ROLE_PEER) || + (local_role == ROLE_PROVIDER && neigh_role == ROLE_CUSTOMER) || + (local_role == ROLE_CUSTOMER && neigh_role == ROLE_PROVIDER) || + (local_role == ROLE_RS_SERVER && neigh_role == ROLE_RS_CLIENT) || + (local_role == ROLE_RS_CLIENT && neigh_role == ROLE_RS_SERVER))) { + bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_ROLE_MISMATCH); + return true; + } + if (neigh_role == ROLE_UNDEFINE && + CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_MODE)) { + const char *err_msg = + "Strict mode. Please set the role on your side."; + bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_ROLE_MISMATCH, + (uint8_t *)err_msg, strlen(err_msg)); + return true; + } + return false; +} + + /* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ @@ -1297,6 +1347,10 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, ? BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE : BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE; + /* Check that roles are corresponding to each other */ + if (bgp_role_violation(peer)) + return -1; + /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_capability @@ -1674,6 +1728,16 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE); stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN); + /* Role*/ + if (peer->local_role != ROLE_UNDEFINE) { + SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + stream_putc(s, CAPABILITY_CODE_ROLE_LEN + 2); + stream_putc(s, CAPABILITY_CODE_ROLE); + stream_putc(s, CAPABILITY_CODE_ROLE_LEN); + stream_putc(s, peer->local_role); + } + /* AddPath */ FOREACH_AFI_SAFI (afi, safi) { if (peer->afc[afi][safi]) { |
