summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c6
-rw-r--r--proto/bgp/bgp.c101
-rw-r--r--proto/bgp/bgp.h17
-rw-r--r--proto/bgp/config.Y29
-rw-r--r--proto/bgp/packets.c84
5 files changed, 194 insertions, 43 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 9387ddba..4346cd5d 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1152,6 +1152,12 @@ bgp_attr_known(uint code)
return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name;
}
+const char *
+bgp_attr_name(uint code)
+{
+ return (code < ARRAY_SIZE(bgp_attr_table)) ? bgp_attr_table[code].name : NULL;
+}
+
void bgp_fix_attr_flags(ea_list *attrs)
{
for (u8 i = 0; i < attrs->count; i++)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index f8146bdf..9d4671af 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -375,6 +375,8 @@ bgp_close_conn(struct bgp_conn *conn)
conn->keepalive_timer = NULL;
rfree(conn->hold_timer);
conn->hold_timer = NULL;
+ rfree(conn->send_hold_timer);
+ conn->send_hold_timer = NULL;
rfree(conn->tx_ev);
conn->tx_ev = NULL;
rfree(conn->sk);
@@ -546,9 +548,6 @@ bgp_conn_enter_openconfirm_state(struct bgp_conn *conn)
bgp_conn_set_state(conn, BS_OPENCONFIRM);
}
-static const struct bgp_af_caps dummy_af_caps = { };
-static const struct bgp_af_caps basic_af_caps = { .ready = 1 };
-
void
bgp_conn_enter_established_state(struct bgp_conn *conn)
{
@@ -604,20 +603,6 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
const struct bgp_af_caps *loc = bgp_find_af_caps(local, c->afi);
const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi);
- /* Use default if capabilities were not announced */
- if (!local->length && (c->afi == BGP_AF_IPV4))
- loc = &basic_af_caps;
-
- if (!peer->length && (c->afi == BGP_AF_IPV4))
- rem = &basic_af_caps;
-
- /* Ignore AFIs that were not announced in multiprotocol capability */
- if (!loc || !loc->ready)
- loc = &dummy_af_caps;
-
- if (!rem || !rem->ready)
- rem = &dummy_af_caps;
-
int active = loc->ready && rem->ready;
c->c.disabled = !active;
c->c.reloadable = p->route_refresh || c->cf->import_table;
@@ -690,6 +675,13 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
p->channel_map[c->index] = c;
}
+ /* Breaking rx_hook for simulating receive problem */
+ if (p->cf->disable_rx)
+ {
+ conn->sk->rx_hook = NULL;
+ tm_stop(conn->hold_timer);
+ }
+
/* proto_notify_state() will likely call bgp_feed_begin(), setting c->feed_state */
bgp_conn_set_state(conn, BS_ESTABLISHED);
@@ -1061,6 +1053,27 @@ bgp_keepalive_timeout(timer *t)
ev_run(conn->tx_ev);
}
+void
+bgp_send_hold_timeout(timer *t)
+{
+ struct bgp_conn *conn = t->data;
+ struct bgp_proto *p = conn->bgp;
+
+ if (conn->state == BS_CLOSE)
+ return;
+
+ /* Error codes not yet assigned by IANA */
+ uint code = 4;
+ uint subcode = 1;
+
+ /* Like bgp_error() but without NOTIFICATION */
+ bgp_log_error(p, BE_BGP_TX, "Error", code, subcode, NULL, 0);
+ bgp_store_error(p, conn, BE_BGP_TX, (code << 16) | subcode);
+ bgp_conn_enter_idle_state(conn);
+ bgp_update_startup_delay(p);
+ bgp_stop(p, 0, NULL, 0);
+}
+
static void
bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
{
@@ -1075,6 +1088,7 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
conn->connect_timer = tm_new_init(p->p.pool, bgp_connect_timeout, conn, 0, 0);
conn->hold_timer = tm_new_init(p->p.pool, bgp_hold_timeout, conn, 0, 0);
conn->keepalive_timer = tm_new_init(p->p.pool, bgp_keepalive_timeout, conn, 0, 0);
+ conn->send_hold_timer = tm_new_init(p->p.pool, bgp_send_hold_timeout, conn, 0, 0);
conn->tx_ev = ev_new_init(p->p.pool, bgp_kick_tx, conn);
}
@@ -2017,6 +2031,21 @@ bgp_postconfig(struct proto_config *CF)
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_enhanced_refresh && !(cf->enable_refresh && cf->enable_enhanced_refresh))
+ cf_warn("Enhanced refresh required but disabled");
+
+ if (cf->require_as4 && !cf->enable_as4)
+ cf_warn("AS4 support required but disabled");
+
+ if (cf->require_extended_messages && !cf->enable_extended_messages)
+ cf_warn("Extended messages required but not enabled");
+
+ if (cf->require_gr && !cf->gr_mode)
+ cf_warn("Graceful restart required but not enabled");
+
+ if (cf->require_llgr && !cf->llgr_mode)
+ cf_warn("Long-lived graceful restart required but not enabled");
+
if (cf->require_roles && (cf->local_role == BGP_ROLE_UNDEFINED))
cf_error("Local role must be set if roles are required");
@@ -2140,6 +2169,12 @@ bgp_postconfig(struct proto_config *CF)
if (cc->secondary && !cc->c.table->sorted)
cf_error("BGP with secondary option requires sorted table");
+
+ if (cc->require_ext_next_hop && !cc->ext_next_hop)
+ cf_warn("Extended next hop required but not enabled");
+
+ if (cc->require_add_path && !cc->add_path)
+ cf_warn("ADD-PATH required but not enabled");
}
}
@@ -2184,20 +2219,30 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
if (C->stale)
same = proto_configure_channel(P, &C, NULL) && same;
- if (same)
- proto_setup_mpls_map(P, RTS_BGP, 1);
+ /* Reset name counter */
+ p->dynamic_name_counter = 0;
- if (same && (p->start_state > BSS_PREPARE))
- bgp_update_bfd(p, new->bfd);
+ if (!same)
+ return 0;
/* We should update our copy of configuration ptr as old configuration will be freed */
- if (same)
- p->cf = new;
+ p->cf = new;
- /* Reset name counter */
- p->dynamic_name_counter = 0;
+ /* Check whether existing connections are compatible with required capabilities */
+ struct bgp_conn *ci = &p->incoming_conn;
+ if (((ci->state == BS_OPENCONFIRM) || (ci->state == BS_ESTABLISHED)) && !bgp_check_capabilities(ci))
+ return 0;
+
+ struct bgp_conn *co = &p->outgoing_conn;
+ if (((co->state == BS_OPENCONFIRM) || (co->state == BS_ESTABLISHED)) && !bgp_check_capabilities(co))
+ return 0;
- return same;
+ proto_setup_mpls_map(P, RTS_BGP, 1);
+
+ if (p->start_state > BSS_PREPARE)
+ bgp_update_bfd(p, new->bfd);
+
+ return 1;
}
#define TABLE(cf, NAME) ((cf)->NAME ? (cf)->NAME->table : NULL )
@@ -2605,7 +2650,9 @@ bgp_show_proto_info(struct proto *P)
tm_remains(p->conn->hold_timer), p->conn->hold_time);
cli_msg(-1006, " Keepalive timer: %t/%u",
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
- }
+ cli_msg(-1006, " Send hold timer: %t/%u",
+ tm_remains(p->conn->send_hold_timer), p->conn->send_hold_time);
+}
#if 0
struct bgp_stats *s = &p->stats;
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 1ba3de5e..7127bc88 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -117,6 +117,8 @@ struct bgp_config {
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 */
+ int send_hold_time;
+ int disable_rx; /* Stop reading messages after handshake (for simulating error) */
/* Times below are in seconds */
unsigned gr_time; /* Graceful restart timeout */
unsigned llgr_time; /* Long-lived graceful restart stale time */
@@ -138,6 +140,13 @@ struct bgp_config {
const char *dynamic_name; /* Name pattern for dynamic BGP */
int dynamic_name_digits; /* Minimum number of digits for dynamic names */
int check_link; /* Use iface link state for liveness detection */
+ int require_refresh; /* Require remote support for route refresh [RFC 2918] */
+ int require_enhanced_refresh; /* Require remote support for enhanced route refresh [RFC 7313] */
+ int require_as4; /* Require remote support for 4B AS numbers [RFC 6793] */
+ int require_extended_messages; /* Require remote support for extended messages [RFC 8654] */
+ int require_hostname; /* Require remote support for hostname [draft] */
+ int require_gr; /* Require remote support for graceful restart [RFC 4724] */
+ int require_llgr; /* Require remote support for long-lived graceful restart [draft] */
struct bfd_options *bfd; /* Use BFD for liveness detection */
};
@@ -159,7 +168,9 @@ struct bgp_channel_config {
u8 llgr_able; /* Allow full long-lived GR for the channel */
uint llgr_time; /* Long-lived graceful restart stale time */
u8 ext_next_hop; /* Allow both IPv4 and IPv6 next hops */
+ u8 require_ext_next_hop; /* Require remote support of IPv4 NLRI with IPv6 next hops [RFC 8950] */
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
+ u8 require_add_path; /* Require remote support of ADD-PATH extension [RFC 7911] */
u8 aigp; /* AIGP is allowed on this session */
u8 aigp_originate; /* AIGP is originated automatically */
u32 cost; /* IGP cost for direct next hops */
@@ -298,6 +309,7 @@ struct bgp_conn {
timer *connect_timer;
timer *hold_timer;
timer *keepalive_timer;
+ timer *send_hold_timer;
event *tx_ev;
u32 packets_to_send; /* Bitmap of packet types to be sent */
u32 channels_to_send; /* Bitmap of channels with packets to be sent */
@@ -306,7 +318,7 @@ struct bgp_conn {
int notify_code, notify_subcode, notify_size;
byte *notify_data;
- uint hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
+ uint hold_time, keepalive_time, send_hold_time; /* Times calculated from my and neighbor's requirements */
};
struct bgp_proto {
@@ -549,6 +561,7 @@ void bgp_conn_enter_openconfirm_state(struct bgp_conn *conn);
void bgp_conn_enter_established_state(struct bgp_conn *conn);
void bgp_conn_enter_close_state(struct bgp_conn *conn);
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
+void broke_bgp_listening(struct channel *C);
void bgp_handle_graceful_restart(struct bgp_proto *p);
void bgp_graceful_restart_done(struct bgp_channel *c);
void bgp_refresh_begin(struct bgp_channel *c);
@@ -611,6 +624,7 @@ bgp_unset_attr(ea_list **to, struct linpool *pool, uint code)
int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
+const char * bgp_attr_name(uint code);
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
void bgp_finish_attrs(struct bgp_parse_state *s, rta *a);
@@ -656,6 +670,7 @@ bgp_total_aigp_metric(rte *r)
void bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new);
void bgp_prepare_capabilities(struct bgp_conn *conn);
+int bgp_check_capabilities(struct bgp_conn *conn);
const struct bgp_af_desc *bgp_get_af_desc(u32 afi);
const struct bgp_af_caps *bgp_find_af_caps(struct bgp_caps *caps, u32 afi);
void bgp_schedule_packet(struct bgp_conn *conn, struct bgp_channel *c, int type);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index e7a2f5cb..1173ff06 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -32,7 +32,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
FIRST, FREE, VALIDATE, BASE, ROLE, ROLES, PEER, PROVIDER, CUSTOMER,
- RS_SERVER, RS_CLIENT, REQUIRE, BGP_OTC, GLOBAL)
+ RS_SERVER, RS_CLIENT, REQUIRE, BGP_OTC, GLOBAL, SEND)
%type <i> bgp_nh
%type <i32> bgp_afi
@@ -77,6 +77,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->local_role = BGP_ROLE_UNDEFINED;
BGP_CFG->dynamic_name = "dynbgp";
BGP_CFG->check_link = -1;
+ BGP_CFG->send_hold_time = -1;
}
;
@@ -182,6 +183,7 @@ bgp_proto:
| bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
| bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; if (($4<1) || ($4>65535)) cf_error("Keepalive time must be in range 1-65535"); }
| bgp_proto MIN KEEPALIVE TIME expr ';' { BGP_CFG->min_keepalive_time = $5; }
+ | bgp_proto SEND HOLD TIME expr';' { BGP_CFG->send_hold_time = $5; }
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
| bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
@@ -191,6 +193,13 @@ bgp_proto:
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
| bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
+ | bgp_proto REQUIRE ROUTE REFRESH bool ';' { BGP_CFG->require_refresh = $5; }
+ | bgp_proto REQUIRE ENHANCED ROUTE REFRESH bool ';' { BGP_CFG->require_enhanced_refresh = $6; }
+ | bgp_proto REQUIRE AS4 bool ';' { BGP_CFG->require_as4 = $4; }
+ | bgp_proto REQUIRE EXTENDED MESSAGES bool ';' { BGP_CFG->require_extended_messages = $5; }
+ | bgp_proto REQUIRE HOSTNAME bool ';' { BGP_CFG->require_hostname = $4; }
+ | bgp_proto REQUIRE GRACEFUL RESTART bool ';' { BGP_CFG->require_gr = $5; }
+ | bgp_proto REQUIRE LONG LIVED GRACEFUL RESTART bool ';' { BGP_CFG->require_llgr = $7; }
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
@@ -215,6 +224,7 @@ bgp_proto:
| 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_proto DISABLE RX bool ';' { BGP_CFG->disable_rx = $4; }
;
bgp_afi:
@@ -284,9 +294,11 @@ bgp_channel_item:
| LONG LIVED GRACEFUL RESTART bool { BGP_CC->llgr_able = $5; }
| LONG LIVED STALE TIME expr { BGP_CC->llgr_time = $5; }
| EXTENDED NEXT HOP bool { BGP_CC->ext_next_hop = $4; }
+ | REQUIRE EXTENDED NEXT HOP bool { BGP_CC->require_ext_next_hop = $5; if (BGP_AFI(BGP_CC->afi) != BGP_AFI_IPV4) cf_warn("Require extended next hop option ignored for non-IPv4 channels"); }
| ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
+ | REQUIRE ADD PATHS bool { BGP_CC->require_add_path = $4; }
| IMPORT TABLE bool { BGP_CC->import_table = $3; }
| EXPORT TABLE bool { BGP_CC->export_table = $3; }
| AIGP bool { BGP_CC->aigp = $2; BGP_CC->aigp_originate = 0; }
@@ -365,12 +377,15 @@ dynamic_attr: BGP_LARGE_COMMUNITY
dynamic_attr: BGP_OTC
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_ONLY_TO_CUSTOMER)); } ;
-custom_attr: ATTRIBUTE BGP NUM type symbol ';' {
- if($3 > 255 || $3 < 1)
- cf_error("Invalid attribute number. (Given %i, must be 1-255.)", $3);
- if($4 != T_BYTESTRING)
- cf_error("Attribute type must be bytestring, not %s.", f_type_name($4));
- struct f_dynamic_attr* a = (struct f_dynamic_attr*) malloc(sizeof(struct f_dynamic_attr));
+custom_attr: ATTRIBUTE BGP expr type symbol ';' {
+ if ($3 > 255 || $3 < 1)
+ cf_error("Invalid attribute number (Given %i, must be 1-255)", $3);
+ if ($4 != T_BYTESTRING)
+ cf_error("Attribute type must be bytestring, not %s", f_type_name($4));
+ if (bgp_attr_name($3))
+ cf_error("Attribute BGP.%d already known as %s", $3, bgp_attr_name($3));
+
+ struct f_dynamic_attr *a = cfg_alloc(sizeof(struct f_dynamic_attr));
*a = f_new_dynamic_attr(f_type_attr($4), T_BYTESTRING, EA_CODE(PROTOCOL_BGP, $3));
a->flags = BAF_TRANSITIVE | BAF_OPTIONAL;
cf_define_symbol(new_config, $5, SYM_ATTRIBUTE, attribute, a);
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index b7df5a7a..e8cc4718 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -173,8 +173,11 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf)
/* Capability negotiation as per RFC 5492 */
-const struct bgp_af_caps *
-bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
+static const struct bgp_af_caps dummy_af_caps = { };
+static const struct bgp_af_caps basic_af_caps = { .ready = 1 };
+
+static const struct bgp_af_caps *
+bgp_find_af_caps_(struct bgp_caps *caps, u32 afi)
{
struct bgp_af_caps *ac;
@@ -185,6 +188,23 @@ bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
return NULL;
}
+const struct bgp_af_caps *
+bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
+{
+ const struct bgp_af_caps *ac = bgp_find_af_caps_(caps, afi);
+
+ /* Return proper capability if found */
+ if (ac)
+ return ac;
+
+ /* Use default if capabilities were not announced */
+ if (!caps->length && (afi == BGP_AF_IPV4))
+ return &basic_af_caps;
+
+ /* Ignore AFIs that were not announced in multiprotocol capability */
+ return &dummy_af_caps;
+}
+
static struct bgp_af_caps *
bgp_get_af_caps(struct bgp_caps **pcaps, u32 afi)
{
@@ -674,7 +694,7 @@ err:
return -1;
}
-static int
+int
bgp_check_capabilities(struct bgp_conn *conn)
{
struct bgp_proto *p = conn->bgp;
@@ -686,21 +706,54 @@ bgp_check_capabilities(struct bgp_conn *conn)
/* This is partially overlapping with bgp_conn_enter_established_state(),
but we need to run this just after we receive OPEN message */
+ if (p->cf->require_refresh && !remote->route_refresh)
+ return 0;
+
+ if (p->cf->require_enhanced_refresh && !remote->enhanced_refresh)
+ return 0;
+
+ if (p->cf->require_as4 && !remote->as4_support)
+ return 0;
+
+ if (p->cf->require_extended_messages && !remote->ext_messages)
+ return 0;
+
+ if (p->cf->require_hostname && !remote->hostname)
+ return 0;
+
+ if (p->cf->require_gr && !remote->gr_aware)
+ return 0;
+
+ if (p->cf->require_llgr && !remote->llgr_aware)
+ return 0;
+
+ /* No check for require_roles, as it uses error code 2.11 instead of 2.7 */
+
BGP_WALK_CHANNELS(p, c)
{
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)));
+ int active = loc->ready && rem->ready;
/* Mandatory must be active */
if (c->cf->mandatory && !active)
return 0;
if (active)
+ {
+ if (c->cf->require_ext_next_hop && !rem->ext_next_hop)
+ return 0;
+
+ if (c->cf->require_add_path && (loc->add_path & BGP_ADD_PATH_RX) && !(rem->add_path & BGP_ADD_PATH_TX))
+ return 0;
+
+ if (c->cf->require_add_path && (loc->add_path & BGP_ADD_PATH_TX) && !(rem->add_path & BGP_ADD_PATH_RX))
+ return 0;
+
count++;
+ }
}
/* We need at least one channel active */
@@ -873,6 +926,10 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
(p->cf->keepalive_time * hold_time / p->cf->hold_time) :
hold_time / 3;
+ uint send_hold_time = (p->cf->send_hold_time >= 0) ?
+ (p->cf->send_hold_time * hold_time / p->cf->hold_time) :
+ 2 * hold_time;
+
/* Keepalive time might be rounded down to zero */
if (hold_time && !keepalive_time)
keepalive_time = 1;
@@ -886,7 +943,7 @@ 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 */
+ /* RFC 5492 5 - check for required capabilities */
if (p->cf->capabilities && !bgp_check_capabilities(conn))
{ bgp_error(conn, 2, 7, NULL, 0); return; }
@@ -981,6 +1038,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
/* Update our local variables */
conn->hold_time = hold_time;
conn->keepalive_time = keepalive_time;
+ conn->send_hold_time = send_hold_time;
conn->as4_session = conn->local_caps->as4_support && caps->as4_support;
conn->ext_messages = conn->local_caps->ext_messages && caps->ext_messages;
p->remote_id = id;
@@ -990,6 +1048,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
bgp_schedule_packet(conn, NULL, PKT_KEEPALIVE);
bgp_start_timer(conn->hold_timer, conn->hold_time);
+ bgp_start_timer(conn->send_hold_timer, conn->send_hold_time);
bgp_conn_enter_openconfirm_state(conn);
}
@@ -2440,7 +2499,7 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck,
.proto = p,
.channel = c,
.pool = tmp_linpool,
- .mp_reach = (c->afi != BGP_AF_IPV4) || (rem && rem->ext_next_hop),
+ .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop,
.as4_session = 1,
.add_path = c->add_path_rx,
.mpls = c->desc->mpls,
@@ -3007,7 +3066,11 @@ bgp_send(struct bgp_conn *conn, uint type, uint len)
put_u16(buf+16, len);
buf[18] = type;
- return sk_send(sk, len);
+ int success = sk_send(sk, len);
+ if (success && ((conn->state == BS_ESTABLISHED) || (conn->state == BS_OPENCONFIRM)))
+ bgp_start_timer(conn->send_hold_timer, conn->send_hold_time);
+
+ return success;
}
/**
@@ -3167,6 +3230,10 @@ bgp_tx(sock *sk)
{
struct bgp_conn *conn = sk->data;
+ /* Pending message was passed to kernel */
+ if ((conn->state == BS_ESTABLISHED) || (conn->state == BS_OPENCONFIRM))
+ bgp_start_timer(conn->send_hold_timer, conn->send_hold_time);
+
DBG("BGP: TX hook\n");
uint max = 1024;
while (--max && (bgp_fire_tx(conn) > 0))
@@ -3208,6 +3275,7 @@ static struct {
{ 3, 10, "Invalid network field" },
{ 3, 11, "Malformed AS_PATH" },
{ 4, 0, "Hold timer expired" },
+ { 4, 1, "Send hold timer expired" }, /* Provisional [draft-ietf-idr-bgp-sendholdtimer] */
{ 5, 0, "Finite state machine error" }, /* Subcodes are according to [RFC6608] */
{ 5, 1, "Unexpected message in OpenSent state" },
{ 5, 2, "Unexpected message in OpenConfirm state" },