diff --git a/lib/socket.h b/lib/socket.h index 03c15dcd..90dcc600 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -93,6 +93,7 @@ void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */ void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */ void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */ void sk_dump_all(void); +void sk_free(resource *r); int sk_is_ipv4(sock *s); /* True if socket is IPv4 */ int sk_is_ipv6(sock *s); /* True if socket is IPv6 */ diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index acae659e..f1446fe2 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -166,6 +166,9 @@ enum bmp_term_reason { // Default chunk size request when memory allocation #define DEFAULT_MEM_BLOCK_SIZE 4096 +// Timeout for connection to the BMP collector +#define CONNECT_TIMEOUT_SEC (10 S) + // Timeout for connection to the BMP collector retry #define CONNECT_RETRY_SEC (10 S) @@ -188,10 +191,17 @@ enum bmp_term_reason { } while (0) +// Callback after successfully connected to BMP station +static void +bmp_station_connected(struct birdsock *sk); + // Handle BIRD socket error event static void bmp_sock_err(sock *sk, int err); +static void +bmp_connection_retry(timer *t); + static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, const byte* tx_data, const size_t tx_data_size, @@ -292,6 +302,7 @@ bmp_fire_tx(void *p_) "Called BMP TX event handler when there is not any data to send" ); + int rv; size_t cnt = 0; // Counts max packets which we want to send per TX slot struct bmp_data_node *tx_data; struct bmp_data_node *tx_data_next; @@ -304,14 +315,18 @@ bmp_fire_tx(void *p_) size_t data_size = tx_data->data_size; memcpy(buf, tx_data->data, tx_data->data_size); + rv = sk_send(p->sk, data_size); + if (rv < 0) { + log(L_ERR "Failed to send BMP PDU"); + return; + } + mb_free(tx_data->data); rem_node((node *) tx_data); mb_free(tx_data); - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - (sk_send(p->sk, data_size) <= 0), - "Failed to send BMP packet" - ); - + if (rv == 0) { + return; + } // BMP packets should be treat with lowest priority when scheduling sending // packets to target. That's why we want to send max. 32 packets per event // call @@ -336,6 +351,7 @@ bmp_tx(struct birdsock *sk) static inline int bmp_open_socket(struct bmp_proto *p) { + p->sk_err = 0; sock *s = p->sk; s->daddr = p->station_ip; s->dport = p->station_port; @@ -349,6 +365,22 @@ bmp_open_socket(struct bmp_proto *p) return rc; } +static void +bmp_connection_timeout(timer *t) +{ + struct bmp_proto *p = t->data; + if (p->sk_err == ECONNREFUSED) { + if (sk_open(p->sk) < 0) + sk_log_error(p->sk, p->p.name); + + p->sk_err = 0; + } + else { + log(L_DEBUG "Successfully connected to BMP station"); + tm_stop(t); + } +} + static void bmp_connection_retry(timer *t) { @@ -356,10 +388,11 @@ bmp_connection_retry(timer *t) if (bmp_open_socket(p) < 0) { - log(L_DEBUG "Failed to connect to BMP station"); return; } + p->sk->tx_hook = bmp_station_connected; + p->sk->err_hook = bmp_sock_err; log(L_DEBUG "Connected to BMP station after connection retry"); tm_stop(t); } @@ -367,8 +400,13 @@ bmp_connection_retry(timer *t) void bmp_sock_err(sock *sk, int err) { - // There is not special case to handle error. - // Thanks for that we avoid flooding by logs. + if (err == ECONNREFUSED) + { + struct bmp_proto *p = sk->data; + p->sk_err = err; + sk_free((resource *)p->sk); + tm_start(p->connect_retry_timer, CONNECT_RETRY_SEC); + } } static inline void @@ -517,15 +555,19 @@ bmp_open(const struct proto *P) p->connect_retry_timer = NULL; if (bmp_open_socket(p) < 0) { - log(L_DEBUG "Failed to connect to BMP station"); + log(L_DEBUG "Failed to connect to BMP station immediately"); p->connect_retry_timer = tm_new_init(P->pool, bmp_connection_retry, p, CONNECT_RETRY_SEC, 0 /* not randomized */); tm_start(p->connect_retry_timer, CONNECT_RETRY_SEC); - p->station_connected = false; } else { - log(L_DEBUG "Connected to BMP station"); + // This is extra check if BMP has been successfully connected to the BMP station, + // because if service is not running on the server, then sk_open() still returns + // success + p->connect_retry_timer = tm_new_init(P->pool, bmp_connection_timeout, p, + CONNECT_TIMEOUT_SEC, 0 /* not randomized */); + tm_start(p->connect_retry_timer, CONNECT_TIMEOUT_SEC); } } @@ -1042,7 +1084,7 @@ bmp_send_termination_msg(struct bmp_proto *p, IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( sk_send(p->sk, bmp_buffer_pos(&stream)) < 0, "Failed to send BMP termination message" - ); + ); bmp_buffer_free(&stream); } diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index a43827b3..902d570c 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -83,6 +83,7 @@ struct bmp_proto { struct rt_table_info rt_table_in_pre_policy; // Pre-policy route import table bool station_connected; // Flag that stores connection status with BMP station bool started; // Flag that stores running status of BMP instance + int sk_err; // Stores last socket error code }; /** diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 5e4d9573..2875e179 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -792,7 +792,7 @@ sk_ssh_free(sock *s) } #endif -static void +void sk_free(resource *r) { sock *s = (sock *) r;