There was actually a second potential deadlock. I fixed both of them and systematically annotated the functions, hopefully preventing the problem in the future.
--- lib/bfd.c | 66 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/bfd.c b/lib/bfd.c index 054a6ae..aa9a627 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -188,6 +188,7 @@ static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; static struct hmap all_bfds__ = HMAP_INITIALIZER(&all_bfds__); static struct hmap *all_bfds OVS_GUARDED_BY(mutex) = &all_bfds__; +static bool bfd_forwarding__(const struct bfd *) OVS_REQ_WRLOCK(mutex); static bool bfd_in_poll(const struct bfd *) OVS_REQ_WRLOCK(&mutex); static void bfd_poll(struct bfd *bfd) OVS_REQ_WRLOCK(&mutex); static const char *bfd_diag_str(enum diag) OVS_REQ_WRLOCK(&mutex); @@ -216,19 +217,12 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 20); /* Returns true if the interface on which 'bfd' is running may be used to * forward traffic according to the BFD session state. */ bool -bfd_forwarding(const struct bfd *bfd) +bfd_forwarding(const struct bfd *bfd) OVS_LOCKS_EXCLUDED(mutex) { bool ret; ovs_mutex_lock(&mutex); - if (bfd->forwarding_override != -1) { - ret = bfd->forwarding_override == 1; - } else { - ret = bfd->state == STATE_UP - && bfd->rmt_diag != DIAG_PATH_DOWN - && bfd->rmt_diag != DIAG_CPATH_DOWN - && bfd->rmt_diag != DIAG_RCPATH_DOWN; - } + ret = bfd_forwarding__(bfd); ovs_mutex_unlock(&mutex); return ret; } @@ -237,9 +231,10 @@ bfd_forwarding(const struct bfd *bfd) * intended for the OVS database. */ void bfd_get_status(const struct bfd *bfd, struct smap *smap) + OVS_LOCKS_EXCLUDED(mutex) { ovs_mutex_lock(&mutex); - smap_add(smap, "forwarding", bfd_forwarding(bfd) ? "true" : "false"); + smap_add(smap, "forwarding", bfd_forwarding__(bfd)? "true" : "false"); smap_add(smap, "state", bfd_state_str(bfd->state)); smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag)); @@ -256,8 +251,8 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap) * handle for the session, or NULL if BFD is not enabled according to 'cfg'. * Also returns NULL if cfg is NULL. */ struct bfd * -bfd_configure(struct bfd *bfd, const char *name, - const struct smap *cfg) +bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg) + OVS_LOCKS_EXCLUDED(mutex) { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; static atomic_uint16_t udp_src = ATOMIC_VAR_INIT(0); @@ -352,7 +347,7 @@ bfd_ref(const struct bfd *bfd_) } void -bfd_unref(struct bfd *bfd) +bfd_unref(struct bfd *bfd) OVS_LOCKS_EXCLUDED(mutex) { if (bfd) { int orig; @@ -370,7 +365,7 @@ bfd_unref(struct bfd *bfd) } void -bfd_wait(const struct bfd *bfd) +bfd_wait(const struct bfd *bfd) OVS_LOCKS_EXCLUDED(mutex) { ovs_mutex_lock(&mutex); if (bfd->flags & FLAG_FINAL) { @@ -385,7 +380,7 @@ bfd_wait(const struct bfd *bfd) } void -bfd_run(struct bfd *bfd) +bfd_run(struct bfd *bfd) OVS_LOCKS_EXCLUDED(mutex) { ovs_mutex_lock(&mutex); if (bfd->state > STATE_DOWN && time_msec() >= bfd->detect_time) { @@ -399,7 +394,7 @@ bfd_run(struct bfd *bfd) } bool -bfd_should_send_packet(const struct bfd *bfd) +bfd_should_send_packet(const struct bfd *bfd) OVS_LOCKS_EXCLUDED(mutex) { bool ret; ovs_mutex_lock(&mutex); @@ -410,7 +405,7 @@ bfd_should_send_packet(const struct bfd *bfd) void bfd_put_packet(struct bfd *bfd, struct ofpbuf *p, - uint8_t eth_src[ETH_ADDR_LEN]) + uint8_t eth_src[ETH_ADDR_LEN]) OVS_LOCKS_EXCLUDED(mutex) { long long int min_tx, min_rx; struct udp_header *udp; @@ -504,7 +499,7 @@ bfd_should_process_flow(const struct bfd *bfd, const struct flow *flow, void bfd_process_packet(struct bfd *bfd, const struct flow *flow, - const struct ofpbuf *p) + const struct ofpbuf *p) OVS_LOCKS_EXCLUDED(mutex) { uint32_t rmt_min_rx, pkt_your_disc; enum state rmt_state; @@ -665,15 +660,28 @@ out: ovs_mutex_unlock(&mutex); } +static bool +bfd_forwarding__(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) +{ + if (bfd->forwarding_override != -1) { + return bfd->forwarding_override == 1; + } + + return bfd->state == STATE_UP + && bfd->rmt_diag != DIAG_PATH_DOWN + && bfd->rmt_diag != DIAG_CPATH_DOWN + && bfd->rmt_diag != DIAG_RCPATH_DOWN; +} + /* Helpers. */ static bool -bfd_in_poll(const struct bfd *bfd) +bfd_in_poll(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { return (bfd->flags & FLAG_POLL) != 0; } static void -bfd_poll(struct bfd *bfd) +bfd_poll(struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { if (bfd->state > STATE_DOWN && !bfd_in_poll(bfd) && !(bfd->flags & FLAG_FINAL)) { @@ -686,7 +694,7 @@ bfd_poll(struct bfd *bfd) } static long long int -bfd_min_tx(const struct bfd *bfd) +bfd_min_tx(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { /* RFC 5880 Section 6.8.3 * When bfd.SessionState is not Up, the system MUST set @@ -698,20 +706,20 @@ bfd_min_tx(const struct bfd *bfd) } static long long int -bfd_tx_interval(const struct bfd *bfd) +bfd_tx_interval(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { long long int interval = bfd_min_tx(bfd); return MAX(interval, bfd->rmt_min_rx); } static long long int -bfd_rx_interval(const struct bfd *bfd) +bfd_rx_interval(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { return MAX(bfd->min_rx, bfd->rmt_min_tx); } static void -bfd_set_next_tx(struct bfd *bfd) +bfd_set_next_tx(struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { long long int interval = bfd_tx_interval(bfd); interval -= interval * random_range(26) / 100; @@ -787,7 +795,7 @@ bfd_diag_str(enum diag diag) { static void log_msg(enum vlog_level level, const struct msg *p, const char *message, - const struct bfd *bfd) + const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -819,6 +827,7 @@ log_msg(enum vlog_level level, const struct msg *p, const char *message, static void bfd_set_state(struct bfd *bfd, enum state state, enum diag diag) + OVS_REQ_WRLOCK(mutex) { if (diag == DIAG_NONE && bfd->cpath_down) { diag = DIAG_CPATH_DOWN; @@ -880,7 +889,7 @@ generate_discriminator(void) } static struct bfd * -bfd_find_by_name(const char *name) OVS_REQ_WRLOCK(&mutex) +bfd_find_by_name(const char *name) OVS_REQ_WRLOCK(mutex) { struct bfd *bfd; @@ -896,7 +905,7 @@ static void bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) { ds_put_format(ds, "\tForwarding: %s\n", - bfd_forwarding(bfd) ? "true" : "false"); + bfd_forwarding__(bfd) ? "true" : "false"); ds_put_format(ds, "\tDetect Multiplier: %d\n", bfd->mult); ds_put_format(ds, "\tConcatenated Path Down: %s\n", bfd->cpath_down ? "true" : "false"); @@ -936,7 +945,7 @@ bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQ_WRLOCK(mutex) static void bfd_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux OVS_UNUSED) + void *aux OVS_UNUSED) OVS_LOCKS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; struct bfd *bfd; @@ -966,6 +975,7 @@ out: static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) + OVS_LOCKS_EXCLUDED(mutex) { const char *forward_str = argv[argc - 1]; int forwarding_override; -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev