netdev-linux: Fix self-deadlocks in traffic control code.
[sliver-openvswitch.git] / lib / bfd.c
index d4ac489..6f86f26 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -15,7 +15,9 @@
 #include <config.h>
 #include "bfd.h"
 
+#include <sys/types.h>
 #include <arpa/inet.h>
+#include <netinet/in_systm.h>
 #include <netinet/ip.h>
 
 #include "byte-order.h"
@@ -190,29 +192,29 @@ static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
 static struct hmap all_bfds__ = HMAP_INITIALIZER(&all_bfds__);
 static struct hmap *const 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);
-static const char *bfd_state_str(enum state) OVS_REQ_WRLOCK(&mutex);
-static long long int bfd_min_tx(const struct bfd *) OVS_REQ_WRLOCK(&mutex);
+static bool bfd_forwarding__(const struct bfd *) OVS_REQUIRES(mutex);
+static bool bfd_in_poll(const struct bfd *) OVS_REQUIRES(mutex);
+static void bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex);
+static const char *bfd_diag_str(enum diag) OVS_REQUIRES(mutex);
+static const char *bfd_state_str(enum state) OVS_REQUIRES(mutex);
+static long long int bfd_min_tx(const struct bfd *) OVS_REQUIRES(mutex);
 static long long int bfd_tx_interval(const struct bfd *)
-    OVS_REQ_WRLOCK(&mutex);
+    OVS_REQUIRES(mutex);
 static long long int bfd_rx_interval(const struct bfd *)
-    OVS_REQ_WRLOCK(&mutex);
-static void bfd_set_next_tx(struct bfd *) OVS_REQ_WRLOCK(&mutex);
+    OVS_REQUIRES(mutex);
+static void bfd_set_next_tx(struct bfd *) OVS_REQUIRES(mutex);
 static void bfd_set_state(struct bfd *, enum state, enum diag)
-    OVS_REQ_WRLOCK(&mutex);
-static uint32_t generate_discriminator(void) OVS_REQ_WRLOCK(&mutex);
+    OVS_REQUIRES(mutex);
+static uint32_t generate_discriminator(void) OVS_REQUIRES(mutex);
 static void bfd_put_details(struct ds *, const struct bfd *)
-    OVS_REQ_WRLOCK(&mutex);
+    OVS_REQUIRES(mutex);
 static void bfd_unixctl_show(struct unixctl_conn *, int argc,
                              const char *argv[], void *aux OVS_UNUSED);
 static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *,
                                                 int argc, const char *argv[],
                                                 void *aux OVS_UNUSED);
 static void log_msg(enum vlog_level, const struct msg *, const char *message,
-                    const struct bfd *) OVS_REQ_WRLOCK(&mutex);
+                    const struct bfd *) OVS_REQUIRES(mutex);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 20);
 
@@ -260,6 +262,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg)
     static atomic_uint16_t udp_src = ATOMIC_VAR_INIT(0);
 
     long long int min_tx, min_rx;
+    bool need_poll = false;
     bool cpath_down;
     const char *hwaddr;
     uint8_t ea[ETH_ADDR_LEN];
@@ -314,7 +317,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg)
             || (!bfd_in_poll(bfd) && bfd->cfg_min_tx < bfd->min_tx)) {
             bfd->min_tx = bfd->cfg_min_tx;
         }
-        bfd_poll(bfd);
+        need_poll = true;
     }
 
     min_rx = smap_get_int(cfg, "min_rx", 1000);
@@ -325,7 +328,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg)
             || (!bfd_in_poll(bfd) && bfd->cfg_min_rx > bfd->min_rx)) {
             bfd->min_rx = bfd->cfg_min_rx;
         }
-        bfd_poll(bfd);
+        need_poll = true;
     }
 
     cpath_down = smap_get_bool(cfg, "cpath_down", false);
@@ -334,7 +337,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg)
         if (bfd->diag == DIAG_NONE || bfd->diag == DIAG_CPATH_DOWN) {
             bfd_set_state(bfd, bfd->state, DIAG_NONE);
         }
-        bfd_poll(bfd);
+        need_poll = true;
     }
 
     hwaddr = smap_get(cfg, "bfd_dst_mac");
@@ -346,6 +349,9 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg)
         bfd->eth_dst_set = false;
     }
 
+    if (need_poll) {
+        bfd_poll(bfd);
+    }
     ovs_mutex_unlock(&mutex);
     return bfd;
 }
@@ -515,7 +521,7 @@ bfd_should_process_flow(const struct bfd *bfd, const struct flow *flow,
     return (flow->dl_type == htons(ETH_TYPE_IP)
             && flow->nw_proto == IPPROTO_UDP
             && flow->tp_dst == htons(BFD_DEST_PORT)
-            && (check_tnl_key || flow->tunnel.tun_id == htonll(0)));
+            && (!check_tnl_key || flow->tunnel.tun_id == htonll(0)));
 }
 
 void
@@ -682,7 +688,7 @@ out:
 }
 \f
 static bool
-bfd_forwarding__(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_forwarding__(const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     if (bfd->forwarding_override != -1) {
         return bfd->forwarding_override == 1;
@@ -696,13 +702,13 @@ bfd_forwarding__(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
 
 /* Helpers. */
 static bool
-bfd_in_poll(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_in_poll(const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     return (bfd->flags & FLAG_POLL) != 0;
 }
 
 static void
-bfd_poll(struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     if (bfd->state > STATE_DOWN && !bfd_in_poll(bfd)
         && !(bfd->flags & FLAG_FINAL)) {
@@ -715,7 +721,7 @@ bfd_poll(struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
 }
 
 static long long int
-bfd_min_tx(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_min_tx(const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     /* RFC 5880 Section 6.8.3
      * When bfd.SessionState is not Up, the system MUST set
@@ -727,20 +733,20 @@ bfd_min_tx(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
 }
 
 static long long int
-bfd_tx_interval(const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_tx_interval(const struct bfd *bfd) OVS_REQUIRES(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) OVS_REQ_WRLOCK(mutex)
+bfd_rx_interval(const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     return MAX(bfd->min_rx, bfd->rmt_min_tx);
 }
 
 static void
-bfd_set_next_tx(struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_set_next_tx(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     long long int interval = bfd_tx_interval(bfd);
     interval -= interval * random_range(26) / 100;
@@ -781,6 +787,8 @@ bfd_flag_str(enum flags flags)
         ds_put_cstr(&ds, "poll ");
     }
 
+    /* Do not copy the trailing whitespace. */
+    ds_chomp(&ds, ' ');
     ovs_strlcpy(flag_str, ds_cstr(&ds), sizeof flag_str);
     ds_destroy(&ds);
     return flag_str;
@@ -816,7 +824,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) OVS_REQ_WRLOCK(mutex)
+        const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
 
@@ -848,7 +856,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)
+    OVS_REQUIRES(mutex)
 {
     if (diag == DIAG_NONE && bfd->cpath_down) {
         diag = DIAG_CPATH_DOWN;
@@ -910,7 +918,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_REQUIRES(mutex)
 {
     struct bfd *bfd;
 
@@ -923,7 +931,7 @@ bfd_find_by_name(const char *name) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQ_WRLOCK(mutex)
+bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     ds_put_format(ds, "\tForwarding: %s\n",
                   bfd_forwarding__(bfd) ? "true" : "false");