diff options
Diffstat (limited to 'bgpd/bgp_keepalives.c')
-rw-r--r-- | bgpd/bgp_keepalives.c | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index afa280a79..5a48c7013 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -36,14 +36,14 @@ #include "bgpd/bgp_keepalives.h" /* clang-format on */ -/** +/* * Peer KeepAlive Timer. * Associates a peer with the time of its last keepalive. */ struct pkat { - // the peer to send keepalives to + /* the peer to send keepalives to */ struct peer *peer; - // absolute time of last keepalive sent + /* absolute time of last keepalive sent */ struct timeval last; }; @@ -52,9 +52,6 @@ static pthread_mutex_t *peerhash_mtx; static pthread_cond_t *peerhash_cond; static struct hash *peerhash; -/* Thread control flag. */ -bool bgp_keepalives_thread_run = false; - static struct pkat *pkat_new(struct peer *peer) { struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat)); @@ -100,10 +97,10 @@ static void peer_process(struct hash_backet *hb, void *arg) static struct timeval tolerance = {0, 100000}; - // calculate elapsed time since last keepalive + /* calculate elapsed time since last keepalive */ monotime_since(&pkat->last, &elapsed); - // calculate difference between elapsed time and configured time + /* calculate difference between elapsed time and configured time */ ka.tv_sec = pkat->peer->v_keepalive; timersub(&ka, &elapsed, &diff); @@ -118,10 +115,10 @@ static void peer_process(struct hash_backet *hb, void *arg) bgp_keepalive_send(pkat->peer); monotime(&pkat->last); memset(&elapsed, 0x00, sizeof(struct timeval)); - diff = ka; // time until next keepalive == peer keepalive time + diff = ka; } - // if calculated next update for this peer < current delay, use it + /* if calculated next update for this peer < current delay, use it */ if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <)) *next_update = diff; } @@ -139,29 +136,9 @@ static unsigned int peer_hash_key(void *arg) return (uintptr_t)pkat->peer; } -void bgp_keepalives_init() -{ - peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); - peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); - - // initialize mutex - pthread_mutex_init(peerhash_mtx, NULL); - - // use monotonic clock with condition variable - pthread_condattr_t attrs; - pthread_condattr_init(&attrs); - pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); - pthread_cond_init(peerhash_cond, &attrs); - pthread_condattr_destroy(&attrs); - - // initialize peer hashtable - peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL); -} - +/* Cleanup handler / deinitializer. */ static void bgp_keepalives_finish(void *arg) { - bgp_keepalives_thread_run = false; - if (peerhash) { hash_clean(peerhash, pkat_del); hash_free(peerhash); @@ -177,32 +154,50 @@ static void bgp_keepalives_finish(void *arg) XFREE(MTYPE_TMP, peerhash_cond); } -/** +/* * Entry function for peer keepalive generation pthread. - * - * bgp_keepalives_init() must be called prior to this. */ void *bgp_keepalives_start(void *arg) { + struct frr_pthread *fpt = arg; + fpt->master->owner = pthread_self(); + struct timeval currtime = {0, 0}; struct timeval aftertime = {0, 0}; struct timeval next_update = {0, 0}; struct timespec next_update_ts = {0, 0}; + peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); + peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); + + /* initialize mutex */ + pthread_mutex_init(peerhash_mtx, NULL); + + /* use monotonic clock with condition variable */ + pthread_condattr_t attrs; + pthread_condattr_init(&attrs); + pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); + pthread_cond_init(peerhash_cond, &attrs); + pthread_condattr_destroy(&attrs); + + /* initialize peer hashtable */ + peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL); pthread_mutex_lock(peerhash_mtx); - // register cleanup handler + /* register cleanup handler */ pthread_cleanup_push(&bgp_keepalives_finish, NULL); - bgp_keepalives_thread_run = true; + /* notify anybody waiting on us that we are done starting up */ + frr_pthread_notify_running(fpt); - while (bgp_keepalives_thread_run) { + while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) { if (peerhash->count > 0) pthread_cond_timedwait(peerhash_cond, peerhash_mtx, &next_update_ts); else while (peerhash->count == 0 - && bgp_keepalives_thread_run) + && atomic_load_explicit(&fpt->running, + memory_order_relaxed)) pthread_cond_wait(peerhash_cond, peerhash_mtx); monotime(&currtime); @@ -219,7 +214,7 @@ void *bgp_keepalives_start(void *arg) TIMEVAL_TO_TIMESPEC(&next_update, &next_update_ts); } - // clean up + /* clean up */ pthread_cleanup_pop(1); return NULL; @@ -229,6 +224,12 @@ void *bgp_keepalives_start(void *arg) void bgp_keepalives_on(struct peer *peer) { + if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) + return; + + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); + assert(fpt->running); + /* placeholder bucket data to use for fast key lookups */ static struct pkat holder = {0}; @@ -253,6 +254,12 @@ void bgp_keepalives_on(struct peer *peer) void bgp_keepalives_off(struct peer *peer) { + if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) + return; + + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); + assert(fpt->running); + /* placeholder bucket data to use for fast key lookups */ static struct pkat holder = {0}; @@ -283,10 +290,13 @@ void bgp_keepalives_wake() pthread_mutex_unlock(peerhash_mtx); } -int bgp_keepalives_stop(void **result, struct frr_pthread *fpt) +int bgp_keepalives_stop(struct frr_pthread *fpt, void **result) { - bgp_keepalives_thread_run = false; + assert(fpt->running); + + atomic_store_explicit(&fpt->running, false, memory_order_relaxed); bgp_keepalives_wake(); + pthread_join(fpt->thread, result); return 0; } |