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.c362
1 files changed, 260 insertions, 102 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index f1dfebdc1b..6bdefd0e9b 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -42,6 +42,66 @@
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_memory.h"
+static const struct message capcode_str[] = {
+ {CAPABILITY_CODE_MP, "MultiProtocol Extensions"},
+ {CAPABILITY_CODE_REFRESH, "Route Refresh"},
+ {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"},
+ {CAPABILITY_CODE_RESTART, "Graceful Restart"},
+ {CAPABILITY_CODE_AS4, "4-octet AS number"},
+ {CAPABILITY_CODE_ADDPATH, "AddPath"},
+ {CAPABILITY_CODE_DYNAMIC, "Dynamic"},
+ {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"},
+ {CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)"},
+ {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"},
+ {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"},
+ {CAPABILITY_CODE_FQDN, "FQDN"},
+ {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"},
+ {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"},
+ {CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"},
+ {0}};
+
+/* Minimum sizes for length field of each cap (so not inc. the header) */
+static const size_t cap_minsizes[] = {
+ [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN,
+ [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
+ [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN,
+ [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN,
+ [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
+ [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
+ [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
+ [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN,
+ [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
+ [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
+ [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN,
+ [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
+ [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
+ [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
+ [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
+};
+
+/* value the capability must be a multiple of.
+ * 0-data capabilities won't be checked against this.
+ * Other capabilities whose data doesn't fall on convenient boundaries for this
+ * table should be set to 1.
+ */
+static const size_t cap_modsizes[] = {
+ [CAPABILITY_CODE_MP] = 4,
+ [CAPABILITY_CODE_REFRESH] = 1,
+ [CAPABILITY_CODE_ORF] = 1,
+ [CAPABILITY_CODE_RESTART] = 1,
+ [CAPABILITY_CODE_AS4] = 4,
+ [CAPABILITY_CODE_ADDPATH] = 4,
+ [CAPABILITY_CODE_DYNAMIC] = 1,
+ [CAPABILITY_CODE_DYNAMIC_OLD] = 1,
+ [CAPABILITY_CODE_ENHE] = 6,
+ [CAPABILITY_CODE_REFRESH_OLD] = 1,
+ [CAPABILITY_CODE_ORF_OLD] = 1,
+ [CAPABILITY_CODE_FQDN] = 1,
+ [CAPABILITY_CODE_ENHANCED_RR] = 1,
+ [CAPABILITY_CODE_EXT_MESSAGE] = 1,
+ [CAPABILITY_CODE_LLGR] = 1,
+};
+
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
negotiate remote peer supports extentions or not. But if
remote-peer doesn't supports negotiation process itself. We would
@@ -264,9 +324,9 @@ static int bgp_capability_mp(struct peer *peer, struct capability_header *hdr)
bgp_capability_mp_data(s, &mpc);
if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s OPEN has MP_EXT CAP for afi/safi: %s/%s",
- peer->host, iana_afi2str(mpc.afi),
- iana_safi2str(mpc.safi));
+ zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s",
+ peer->host, lookup_msg(capcode_str, hdr->code, NULL),
+ iana_afi2str(mpc.afi), iana_safi2str(mpc.safi));
/* Convert AFI, SAFI to internal values, check. */
if (bgp_map_afi_safi_iana2int(mpc.afi, mpc.safi, &afi, &safi))
@@ -466,8 +526,6 @@ static int bgp_capability_restart(struct peer *peer,
peer->v_gr_restart = restart_flag_time;
if (bgp_debug_neighbor_events(peer)) {
- zlog_debug("%s OPEN has Graceful Restart capability",
- peer->host);
zlog_debug("%s Peer has%srestarted. Restart Time : %d",
peer->host,
CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV)
@@ -517,6 +575,53 @@ static int bgp_capability_restart(struct peer *peer,
return 0;
}
+static int bgp_capability_llgr(struct peer *peer,
+ struct capability_header *caphdr)
+{
+ struct stream *s = BGP_INPUT(peer);
+ size_t end = stream_get_getp(s) + caphdr->length;
+
+ SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV);
+
+ while (stream_get_getp(s) + 4 <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi = stream_getw(s);
+ iana_safi_t pkt_safi = stream_getc(s);
+ uint8_t flags = stream_getc(s);
+ uint32_t stale_time = stream_get3(s);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Long-lived Graceful Restart capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ } else if (!peer->afc[afi][safi]
+ || !CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_RCV)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Long-lived Graceful Restart capability",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ } else {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %s/%s(afi/safi) Long-lived Graceful Restart capability stale time %u sec",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi), stale_time);
+
+ peer->llgr[afi][safi].flags = flags;
+ peer->llgr[afi][safi].stale_time =
+ MIN(stale_time, peer->bgp->llgr_stale_time);
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_RCV);
+ }
+ }
+
+ return 0;
+}
+
/* Unlike other capability parsing routines, this one returns 0 on error */
static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr)
{
@@ -580,9 +685,10 @@ static int bgp_capability_addpath(struct peer *peer,
if (bgp_debug_neighbor_events(peer))
zlog_debug(
- "%s OPEN has AddPath CAP for afi/safi: %s/%s%s%s",
- peer->host, iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi),
+ "%s OPEN has %s capability for afi/safi: %s/%s%s%s",
+ peer->host,
+ lookup_msg(capcode_str, hdr->code, NULL),
+ iana_afi2str(pkt_afi), iana_safi2str(pkt_safi),
(send_receive & BGP_ADDPATH_RX) ? ", receive"
: "",
(send_receive & BGP_ADDPATH_TX) ? ", transmit"
@@ -763,63 +869,6 @@ static int bgp_capability_hostname(struct peer *peer,
return 0;
}
-static const struct message capcode_str[] = {
- {CAPABILITY_CODE_MP, "MultiProtocol Extensions"},
- {CAPABILITY_CODE_REFRESH, "Route Refresh"},
- {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"},
- {CAPABILITY_CODE_RESTART, "Graceful Restart"},
- {CAPABILITY_CODE_AS4, "4-octet AS number"},
- {CAPABILITY_CODE_ADDPATH, "AddPath"},
- {CAPABILITY_CODE_DYNAMIC, "Dynamic"},
- {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"},
- {CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)"},
- {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"},
- {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"},
- {CAPABILITY_CODE_FQDN, "FQDN"},
- {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"},
- {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"},
- {0}};
-
-/* Minimum sizes for length field of each cap (so not inc. the header) */
-static const size_t cap_minsizes[] = {
- [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN,
- [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
- [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN,
- [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN,
- [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
- [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
- [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
- [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN,
- [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
- [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
- [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN,
- [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
- [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
- [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
-};
-
-/* value the capability must be a multiple of.
- * 0-data capabilities won't be checked against this.
- * Other capabilities whose data doesn't fall on convenient boundaries for this
- * table should be set to 1.
- */
-static const size_t cap_modsizes[] = {
- [CAPABILITY_CODE_MP] = 4,
- [CAPABILITY_CODE_REFRESH] = 1,
- [CAPABILITY_CODE_ORF] = 1,
- [CAPABILITY_CODE_RESTART] = 1,
- [CAPABILITY_CODE_AS4] = 4,
- [CAPABILITY_CODE_ADDPATH] = 4,
- [CAPABILITY_CODE_DYNAMIC] = 1,
- [CAPABILITY_CODE_DYNAMIC_OLD] = 1,
- [CAPABILITY_CODE_ENHE] = 6,
- [CAPABILITY_CODE_REFRESH_OLD] = 1,
- [CAPABILITY_CODE_ORF_OLD] = 1,
- [CAPABILITY_CODE_FQDN] = 1,
- [CAPABILITY_CODE_ENHANCED_RR] = 1,
- [CAPABILITY_CODE_EXT_MESSAGE] = 1,
-};
-
/**
* Parse given capability.
* XXX: This is reading into a stream, but not using stream API
@@ -955,6 +1004,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_RESTART:
ret = bgp_capability_restart(peer, &caphdr);
break;
+ case CAPABILITY_CODE_LLGR:
+ ret = bgp_capability_llgr(peer, &caphdr);
+ break;
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV);
@@ -1046,7 +1098,7 @@ static bool strict_capability_same(struct peer *peer)
/* peek into option, stores ASN to *as4 if the AS4 capability was found.
* Returns 0 if no as4 found, as4cap value otherwise.
*/
-as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
+as_t peek_for_as4_capability(struct peer *peer, uint16_t length)
{
struct stream *s = BGP_INPUT(peer);
size_t orig_getp = stream_get_getp(s);
@@ -1062,7 +1114,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
*/
while (stream_get_getp(s) < end) {
uint8_t opt_type;
- uint8_t opt_length;
+ uint16_t opt_length;
/* Check the length. */
if (stream_get_getp(s) + 2 > end)
@@ -1070,7 +1122,9 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
/* Fetch option type and length. */
opt_type = stream_getc(s);
- opt_length = stream_getc(s);
+ opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
+ ? stream_getw(s)
+ : stream_getc(s);
/* Option length check. */
if (stream_get_getp(s) + opt_length > end)
@@ -1118,7 +1172,8 @@ end:
*
* @param[out] mp_capability @see bgp_capability_parse() for semantics.
*/
-int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
+int bgp_open_option_parse(struct peer *peer, uint16_t length,
+ int *mp_capability)
{
int ret = 0;
uint8_t *error;
@@ -1137,7 +1192,7 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
while (stream_get_getp(s) < end) {
uint8_t opt_type;
- uint8_t opt_length;
+ uint16_t opt_length;
/* Must have at least an OPEN option header */
if (STREAM_READABLE(s) < 2) {
@@ -1149,11 +1204,14 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
/* Fetch option type and length. */
opt_type = stream_getc(s);
- opt_length = stream_getc(s);
+ opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
+ ? stream_getw(s)
+ : stream_getc(s);
/* Option length check. */
if (STREAM_READABLE(s) < opt_length) {
- zlog_info("%s Option length error", peer->host);
+ zlog_info("%s Option length error (%d)", peer->host,
+ opt_length);
bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
@@ -1257,9 +1315,10 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
}
static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
- afi_t afi, safi_t safi, uint8_t code)
+ afi_t afi, safi_t safi, uint8_t code,
+ bool ext_opt_params)
{
- uint8_t cap_len;
+ uint16_t cap_len;
uint8_t orf_len;
unsigned long capp;
unsigned long orfp;
@@ -1273,7 +1332,8 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
stream_putc(s, BGP_OPEN_OPT_CAP);
capp = stream_get_endp(s); /* Set Capability Len Pointer */
- stream_putc(s, 0); /* Capability Length */
+ ext_opt_params ? stream_putw(s, 0)
+ : stream_putc(s, 0); /* Capability Length */
stream_putc(s, code); /* Capability Code */
orfp = stream_get_endp(s); /* Set ORF Len Pointer */
stream_putc(s, 0); /* ORF Length */
@@ -1321,11 +1381,12 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
/* Total Capability Len. */
cap_len = stream_get_endp(s) - capp - 1;
- stream_putc_at(s, capp, cap_len);
+ ext_opt_params ? stream_putw_at(s, capp, cap_len)
+ : stream_putc_at(s, capp, cap_len);
}
static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
- unsigned long cp)
+ bool ext_opt_params)
{
int len;
iana_afi_t pkt_afi;
@@ -1347,7 +1408,8 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
capp = stream_get_endp(s); /* Set Capability Len Pointer */
- stream_putc(s, 0); /* Capability Length */
+ ext_opt_params ? stream_putw(s, 0)
+ : stream_putc(s, 0); /* Capability Length */
stream_putc(s, CAPABILITY_CODE_RESTART);
/* Set Restart Capability Len Pointer */
rcapp = stream_get_endp(s);
@@ -1402,14 +1464,65 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
/* Total Capability Len. */
len = stream_get_endp(s) - capp - 1;
- stream_putc_at(s, capp, len);
+ ext_opt_params ? stream_putw_at(s, capp, len - 1)
+ : stream_putc_at(s, capp, len);
+}
+
+static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer,
+ bool ext_opt_params)
+{
+ int len;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t safi;
+ iana_safi_t pkt_safi;
+ unsigned long capp = 0;
+ unsigned long rcapp = 0;
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV))
+ return;
+
+ SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV);
+
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ capp = stream_get_endp(s); /* Set Capability Len Pointer */
+ ext_opt_params ? stream_putw(s, 0)
+ : stream_putc(s, 0); /* Capability Length */
+ stream_putc(s, CAPABILITY_CODE_LLGR);
+
+ rcapp = stream_get_endp(s);
+ stream_putc(s, 0);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putc(s, LLGR_F_BIT);
+ stream_put3(s, peer->bgp->llgr_stale_time);
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_ADV);
+ }
+
+ /* Total Long-lived Graceful Restart capability Len. */
+ len = stream_get_endp(s) - rcapp - 1;
+ stream_putc_at(s, rcapp, len);
+
+ /* Total Capability Len. */
+ len = stream_get_endp(s) - capp - 1;
+ ext_opt_params ? stream_putw_at(s, capp, len - 1)
+ : stream_putc_at(s, capp, len);
}
/* Fill in capability open option to the packet. */
-void bgp_open_capability(struct stream *s, struct peer *peer)
+uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
+ bool ext_opt_params)
{
- uint8_t len;
- unsigned long cp, capp, rcapp;
+ uint16_t len;
+ unsigned long cp, capp, rcapp, eopl = 0;
iana_afi_t pkt_afi;
afi_t afi;
safi_t safi;
@@ -1418,16 +1531,26 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
uint8_t afi_safi_count = 0;
int adv_addpath_tx = 0;
- /* Remember current pointer for Opt Parm Len. */
+ /* Non-Ext OP Len. */
cp = stream_get_endp(s);
-
- /* Opt Parm Len. */
stream_putc(s, 0);
+ if (ext_opt_params) {
+ /* Non-Ext OP Len. */
+ stream_putc_at(s, cp, BGP_OPEN_NON_EXT_OPT_LEN);
+
+ /* Non-Ext OP Type */
+ stream_putc(s, BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH);
+
+ /* Extended Opt. Parm. Length */
+ eopl = stream_get_endp(s);
+ stream_putw(s, 0);
+ }
+
/* Do not send capability. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
|| CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY))
- return;
+ return 0;
/* MP capability for configured AFI, SAFI */
FOREACH_AFI_SAFI (afi, safi) {
@@ -1438,7 +1561,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
peer->afc_adv[afi][safi] = 1;
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_MP_LEN + 2);
+ ext_opt_params
+ ? stream_putw(s, CAPABILITY_CODE_MP_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_MP_LEN + 2);
stream_putc(s, CAPABILITY_CODE_MP);
stream_putc(s, CAPABILITY_CODE_MP_LEN);
stream_putw(s, pkt_afi);
@@ -1458,7 +1583,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
*/
SET_FLAG(peer->cap, PEER_CAP_ENHE_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_ENHE_LEN + 2);
+ ext_opt_params
+ ? stream_putw(s,
+ CAPABILITY_CODE_ENHE_LEN
+ + 2)
+ : stream_putc(s,
+ CAPABILITY_CODE_ENHE_LEN
+ + 2);
stream_putc(s, CAPABILITY_CODE_ENHE);
stream_putc(s, CAPABILITY_CODE_ENHE_LEN);
@@ -1479,25 +1610,29 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* Route refresh. */
SET_FLAG(peer->cap, PEER_CAP_REFRESH_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
stream_putc(s, CAPABILITY_CODE_REFRESH_OLD);
stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
stream_putc(s, CAPABILITY_CODE_REFRESH);
stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
/* Enhanced Route Refresh. */
SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_ENHANCED_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
stream_putc(s, CAPABILITY_CODE_ENHANCED_RR);
stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN);
/* AS4 */
SET_FLAG(peer->cap, PEER_CAP_AS4_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_AS4_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2);
stream_putc(s, CAPABILITY_CODE_AS4);
stream_putc(s, CAPABILITY_CODE_AS4_LEN);
if (peer->change_local_as)
@@ -1509,7 +1644,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* Extended Message Support */
SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2);
stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE);
stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN);
@@ -1528,7 +1664,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
SET_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) + 2);
+ ext_opt_params
+ ? stream_putw(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count)
+ + 2)
+ : stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count)
+ + 2);
stream_putc(s, CAPABILITY_CODE_ADDPATH);
stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count);
@@ -1575,9 +1715,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
|| CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_RM)) {
bgp_open_capability_orf(s, peer, afi, safi,
- CAPABILITY_CODE_ORF_OLD);
+ CAPABILITY_CODE_ORF_OLD,
+ ext_opt_params);
bgp_open_capability_orf(s, peer, afi, safi,
- CAPABILITY_CODE_ORF);
+ CAPABILITY_CODE_ORF,
+ ext_opt_params);
}
}
@@ -1585,11 +1727,15 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+ ext_opt_params
+ ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
stream_putc(s, CAPABILITY_CODE_DYNAMIC_OLD);
stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+ ext_opt_params
+ ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
stream_putc(s, CAPABILITY_CODE_DYNAMIC);
stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN);
}
@@ -1599,7 +1745,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
rcapp = stream_get_endp(s); /* Ptr to length placeholder */
- stream_putc(s, 0); /* dummy len for now */
+ ext_opt_params ? stream_putw(s, 0)
+ : stream_putc(s, 0); /* Capability Length */
stream_putc(s, CAPABILITY_CODE_FQDN);
capp = stream_get_endp(s);
stream_putc(s, 0); /* dummy len for now */
@@ -1621,7 +1768,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* Set the lengths straight */
len = stream_get_endp(s) - rcapp - 1;
- stream_putc_at(s, rcapp, len);
+ ext_opt_params ? stream_putw_at(s, rcapp, len - 1)
+ : stream_putc_at(s, rcapp, len);
+
len = stream_get_endp(s) - capp - 1;
stream_putc_at(s, capp, len);
@@ -1632,9 +1781,18 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
cmd_domainname_get());
}
- bgp_peer_send_gr_capability(s, peer, cp);
+ bgp_peer_send_gr_capability(s, peer, ext_opt_params);
+ bgp_peer_send_llgr_capability(s, peer, ext_opt_params);
/* Total Opt Parm Len. */
len = stream_get_endp(s) - cp - 1;
- stream_putc_at(s, cp, len);
+
+ if (ext_opt_params) {
+ len = stream_get_endp(s) - eopl - 2;
+ stream_putw_at(s, eopl, len);
+ } else {
+ stream_putc_at(s, cp, len);
+ }
+
+ return len;
}