diff options
Diffstat (limited to 'proto/bgp')
-rw-r--r-- | proto/bgp/attrs.c | 6 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 101 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 17 | ||||
-rw-r--r-- | proto/bgp/config.Y | 29 | ||||
-rw-r--r-- | proto/bgp/packets.c | 84 |
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" }, |