summaryrefslogtreecommitdiff
path: root/bgpd/bgp_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_open.c')
-rw-r--r--bgpd/bgp_open.c64
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]) {