diff options
| -rw-r--r-- | bgpd/bgp_fsm.c | 35 | ||||
| -rw-r--r-- | bgpd/bgp_io.c | 6 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 3 |
3 files changed, 32 insertions, 12 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 7282d81f67..f7c031610d 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -133,10 +133,12 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_connect); - BGP_TIMER_OFF(peer->t_connect_check); + BGP_TIMER_OFF(peer->t_connect_check_r); + BGP_TIMER_OFF(peer->t_connect_check_w); BGP_TIMER_OFF(from_peer->t_routeadv); BGP_TIMER_OFF(from_peer->t_connect); - BGP_TIMER_OFF(from_peer->t_connect_check); + BGP_TIMER_OFF(from_peer->t_connect_check_r); + BGP_TIMER_OFF(from_peer->t_connect_check_w); /* * At this point in time, it is possible that there are packets pending @@ -1072,7 +1074,8 @@ int bgp_stop(struct peer *peer) bgp_writes_off(peer); bgp_reads_off(peer); - THREAD_OFF(peer->t_connect_check); + THREAD_OFF(peer->t_connect_check_r); + THREAD_OFF(peer->t_connect_check_w); /* Stop all timers. */ BGP_TIMER_OFF(peer->t_start); @@ -1209,9 +1212,15 @@ static int bgp_stop_with_notify(struct peer *peer, u_char code, u_char sub_code) * events as appropriate. * * This function is called when setting up a new session. After connect() is - * called on the peer's socket (in bgp_start()), the fd is passed to select() - * to wait for connection success or failure. When select() returns, this + * called on the peer's socket (in bgp_start()), the fd is passed to poll() + * to wait for connection success or failure. When poll() returns, this * function is called to evaluate the result. + * + * Due to differences in behavior of poll() on Linux and BSD - specifically, + * the value of .revents in the case of a closed connection - this function is + * scheduled both for a read and a write event. The write event is triggered + * when the connection is established. A read event is triggered when the + * connection is closed. Thus we need to cancel whichever one did not occur. */ static int bgp_connect_check(struct thread *thread) { @@ -1226,7 +1235,8 @@ static int bgp_connect_check(struct thread *thread) assert(!peer->t_read); assert(!peer->t_write); - peer->t_connect_check = NULL; + THREAD_OFF(peer->t_connect_check_r); + THREAD_OFF(peer->t_connect_check_w); /* Check file descriptor. */ slen = sizeof(status); @@ -1409,11 +1419,18 @@ int bgp_start(struct peer *peer) return -1; } /* - * when the socket becomes ready (or fails to connect), - * bgp_connect_check will be called. + * - when the socket becomes ready, poll() will signify POLLOUT + * - if it fails to connect, poll() will signify POLLHUP + * - POLLHUP is handled as a 'read' event by thread.c + * + * therefore, we schedule both a read and a write event with + * bgp_connect_check() as the handler for each and cancel the + * unused event in that function. */ thread_add_read(bm->master, bgp_connect_check, peer, peer->fd, - &peer->t_connect_check); + &peer->t_connect_check_r); + thread_add_write(bm->master, bgp_connect_check, peer, peer->fd, + &peer->t_connect_check_w); break; } return 0; diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index c3bc0a195d..8ce6276c03 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -120,7 +120,8 @@ void bgp_writes_on(struct peer *peer) assert(peer->obuf); assert(peer->ibuf); assert(peer->ibuf_work); - assert(!peer->t_connect_check); + assert(!peer->t_connect_check_r); + assert(!peer->t_connect_check_w); assert(peer->fd); struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); @@ -156,7 +157,8 @@ void bgp_reads_on(struct peer *peer) assert(peer->ibuf_work); assert(stream_get_endp(peer->ibuf_work) == 0); assert(peer->obuf); - assert(!peer->t_connect_check); + assert(!peer->t_connect_check_r); + assert(!peer->t_connect_check_w); assert(peer->fd); struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 086e59486b..aa83cf5e7e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -807,7 +807,8 @@ struct peer { struct thread *t_read; struct thread *t_write; struct thread *t_start; - struct thread *t_connect_check; + struct thread *t_connect_check_r; + struct thread *t_connect_check_w; struct thread *t_connect; struct thread *t_holdtime; struct thread *t_routeadv; |
