Merge commit '259e0b1ad1bfea762a76f0098deb8f8d8db1dfa3'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 15 Aug 2013 14:11:21 +0000 (16:11 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 15 Aug 2013 14:11:21 +0000 (16:11 +0200)
40 files changed:
CodingStyle
datapath/datapath.c
datapath/flow.c
datapath/flow.h
lib/bfd.c
lib/cfm.c
lib/classifier.c
lib/classifier.h
lib/compiler.h
lib/lacp.c
lib/netdev-bsd.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-linux.h
lib/ofp-util.h
lib/ovs-thread.c
lib/ovs-thread.h
lib/poll-loop.c
lib/random.c
lib/socket-util.c
lib/socket-util.h
lib/stp.c
lib/timeval.c
lib/util.c
lib/vlandev.c
lib/vlog.c
ofproto/connmgr.c
ofproto/ofproto-dpif-ipfix.c
ofproto/ofproto-dpif-sflow.c
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif-xlate.h
ofproto/ofproto-dpif.c
ofproto/ofproto-dpif.h
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/tunnel.c
tests/test-classifier.c
utilities/bugtool/ovs-bugtool.in
utilities/ovs-ofctl.c
vswitchd/system-stats.c

index 55b37a1..2f24ee3 100644 (file)
@@ -298,6 +298,21 @@ the name of each enum.  For example:
     };
 
 
+THREAD SAFETY ANNOTATIONS
+
+  Use the macros in lib/compiler.h to annotate locking requirements.
+For example:
+
+    static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
+    static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
+
+    void function_require_plain_mutex(void) OVS_REQUIRES(mutex);
+    void function_require_rwlock(void) OVS_REQ_RDLOCK(rwlock);
+
+  Pass lock objects, not their addresses, to the annotation macros.
+(Thus we have OVS_REQUIRES(mutex) above, not OVS_REQUIRES(&mutex).)
+
+
 SOURCE FILES
 
   Each source file should state its license in a comment at the very
index e5e0616..190b61b 100644 (file)
@@ -624,7 +624,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
        int err, start;
 
        ovs_match_init(&match, &key, NULL);
-       err = ipv4_tun_from_nlattr(nla_data(attr), &match, false);
+       err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &match, false);
        if (err)
                return err;
 
@@ -1065,8 +1065,8 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
                if (!start)
                        return -EMSGSIZE;
 
-               err = ipv4_tun_to_nlattr(skb,
-                               nla_data(ovs_key), nla_data(ovs_key));
+               err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key),
+                                            nla_data(ovs_key));
                if (err)
                        return err;
                nla_nest_end(skb, start);
index e259e6d..4075350 100644 (file)
@@ -138,7 +138,7 @@ static bool ovs_match_validate(const struct sw_flow_match *match,
        /* Always allowed mask fields. */
        mask_allowed |= ((1ULL << OVS_KEY_ATTR_TUNNEL)
                       | (1ULL << OVS_KEY_ATTR_IN_PORT)
-                      | (11ULL << OVS_KEY_ATTR_ETHERTYPE));
+                      | (1ULL << OVS_KEY_ATTR_ETHERTYPE));
 
        /* Check key attributes. */
        if (match->key->eth.type == htons(ETH_P_ARP)
@@ -1174,8 +1174,8 @@ static int parse_flow_nlattrs(const struct nlattr *attr,
        return __parse_flow_nlattrs(attr, a, attrsp, false);
 }
 
-int ipv4_tun_from_nlattr(const struct nlattr *attr,
-                        struct sw_flow_match *match, bool is_mask)
+int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr,
+                            struct sw_flow_match *match, bool is_mask)
 {
        struct nlattr *a;
        int rem;
@@ -1263,9 +1263,9 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr,
        return 0;
 }
 
-int ipv4_tun_to_nlattr(struct sk_buff *skb,
-                       const struct ovs_key_ipv4_tunnel *tun_key,
-                       const struct ovs_key_ipv4_tunnel *output)
+int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb,
+                          const struct ovs_key_ipv4_tunnel *tun_key,
+                          const struct ovs_key_ipv4_tunnel *output)
 {
        struct nlattr *nla;
 
@@ -1334,7 +1334,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,
                *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK);
        }
        if (*attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
-               if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
+               if (ovs_ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
                                        is_mask))
                        return -EINVAL;
                *attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
@@ -1704,7 +1704,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey,
                goto nla_put_failure;
 
        if ((swkey->tun_key.ipv4_dst || is_mask) &&
-           ipv4_tun_to_nlattr(skb, &swkey->tun_key, &output->tun_key))
+           ovs_ipv4_tun_to_nlattr(skb, &swkey->tun_key, &output->tun_key))
                goto nla_put_failure;
 
        if (swkey->phy.in_port == DP_MAX_PORTS) {
index 59c7f6e..5d15783 100644 (file)
@@ -222,11 +222,11 @@ void ovs_flow_remove(struct flow_table *table, struct sw_flow *flow);
 
 struct sw_flow *ovs_flow_dump_next(struct flow_table *table, u32 *bucket, u32 *idx);
 extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1];
-int ipv4_tun_from_nlattr(const struct nlattr *attr,
-                        struct sw_flow_match *match, bool is_mask);
-int ipv4_tun_to_nlattr(struct sk_buff *skb,
-                       const struct ovs_key_ipv4_tunnel *tun_key,
-                       const struct ovs_key_ipv4_tunnel *output);
+int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr,
+                            struct sw_flow_match *match, bool is_mask);
+int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb,
+                          const struct ovs_key_ipv4_tunnel *tun_key,
+                          const struct ovs_key_ipv4_tunnel *output);
 
 bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
                const struct sw_flow_key *key, int key_len);
index d1b8237..81fd178 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -191,29 +191,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);
 
@@ -683,7 +683,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;
@@ -697,13 +697,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)) {
@@ -716,7 +716,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
@@ -728,20 +728,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;
@@ -817,7 +817,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;
 
@@ -849,7 +849,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;
@@ -911,7 +911,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;
 
@@ -924,7 +924,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");
index 0bd41bf..a238c67 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -156,7 +156,7 @@ static unixctl_cb_func cfm_unixctl_show;
 static unixctl_cb_func cfm_unixctl_set_fault;
 
 static uint64_t
-cfm_rx_packets(const struct cfm *cfm) OVS_REQ_WRLOCK(mutex)
+cfm_rx_packets(const struct cfm *cfm) OVS_REQUIRES(mutex)
 {
     struct netdev_stats stats;
 
@@ -204,7 +204,7 @@ ds_put_cfm_fault(struct ds *ds, int fault)
 }
 
 static void
-cfm_generate_maid(struct cfm *cfm) OVS_REQ_WRLOCK(mutex)
+cfm_generate_maid(struct cfm *cfm) OVS_REQUIRES(mutex)
 {
     const char *ovs_md_name = "ovs";
     const char *ovs_ma_name = "ovs";
@@ -247,7 +247,7 @@ ccm_interval_to_ms(uint8_t interval)
 }
 
 static long long int
-cfm_fault_interval(struct cfm *cfm) OVS_REQ_WRLOCK(mutex)
+cfm_fault_interval(struct cfm *cfm) OVS_REQUIRES(mutex)
 {
     /* According to the 802.1ag specification we should assume every other MP
      * with the same MAID has the same transmission interval that we have.  If
@@ -289,7 +289,7 @@ cfm_is_valid_mpid(bool extended, uint64_t mpid)
 }
 
 static struct remote_mp *
-lookup_remote_mp(const struct cfm *cfm, uint64_t mpid) OVS_REQ_WRLOCK(mutex)
+lookup_remote_mp(const struct cfm *cfm, uint64_t mpid) OVS_REQUIRES(mutex)
 {
     struct remote_mp *rmp;
 
@@ -795,7 +795,7 @@ out:
 }
 
 static int
-cfm_get_fault__(const struct cfm *cfm) OVS_REQ_WRLOCK(mutex)
+cfm_get_fault__(const struct cfm *cfm) OVS_REQUIRES(mutex)
 {
     if (cfm->fault_override >= 0) {
         return cfm->fault_override ? CFM_FAULT_OVERRIDE : 0;
@@ -866,7 +866,7 @@ cfm_get_remote_mpids(const struct cfm *cfm, uint64_t **rmps, size_t *n_rmps)
 }
 
 static struct cfm *
-cfm_find(const char *name) OVS_REQ_WRLOCK(&mutex)
+cfm_find(const char *name) OVS_REQUIRES(mutex)
 {
     struct cfm *cfm;
 
@@ -879,7 +879,7 @@ cfm_find(const char *name) OVS_REQ_WRLOCK(&mutex)
 }
 
 static void
-cfm_print_details(struct ds *ds, const struct cfm *cfm) OVS_REQ_WRLOCK(&mutex)
+cfm_print_details(struct ds *ds, const struct cfm *cfm) OVS_REQUIRES(mutex)
 {
     struct remote_mp *rmp;
     bool extended;
index a717bd3..556278f 100644 (file)
@@ -25,6 +25,7 @@
 #include "odp-util.h"
 #include "ofp-util.h"
 #include "packets.h"
+#include "ovs-thread.h"
 
 static struct cls_table *find_table(const struct classifier *,
                                     const struct minimask *);
@@ -143,6 +144,7 @@ classifier_init(struct classifier *cls)
     cls->n_rules = 0;
     hmap_init(&cls->tables);
     list_init(&cls->tables_priority);
+    ovs_rwlock_init(&cls->rwlock);
 }
 
 /* Destroys 'cls'.  Rules within 'cls', if any, are not freed; this is the
@@ -157,6 +159,7 @@ classifier_destroy(struct classifier *cls)
             destroy_table(cls, table);
         }
         hmap_destroy(&cls->tables);
+        ovs_rwlock_destroy(&cls->rwlock);
     }
 }
 
index a14a24d..3f89196 100644 (file)
  *              a hash map from fixed field values to "struct cls_rule",
  *                      which can contain a list of otherwise identical rules
  *                      with lower priorities.
- */
+ *
+ * Thread-safety
+ * =============
+ *
+ * When locked properly, the classifier is thread safe as long as the following
+ * conditions are satisfied.
+ * - Only the main thread calls functions requiring a write lock.
+ * - Only the main thread is allowed to iterate over rules. */
 
 #include "flow.h"
 #include "hmap.h"
@@ -32,6 +39,8 @@
 #include "match.h"
 #include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
+#include "ovs-thread.h"
+#include "util.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -42,6 +51,7 @@ struct classifier {
     int n_rules;                /* Total number of rules. */
     struct hmap tables;         /* Contains "struct cls_table"s.  */
     struct list tables_priority; /* Tables in descending priority order */
+    struct ovs_rwlock rwlock;
 };
 
 /* A set of rules that all have the same fields wildcarded. */
@@ -88,26 +98,35 @@ bool cls_rule_is_catchall(const struct cls_rule *);
 bool cls_rule_is_loose_match(const struct cls_rule *rule,
                              const struct minimatch *criteria);
 
-void classifier_init(struct classifier *);
+void classifier_init(struct classifier *cls);
 void classifier_destroy(struct classifier *);
-bool classifier_is_empty(const struct classifier *);
-int classifier_count(const struct classifier *);
-void classifier_insert(struct classifier *, struct cls_rule *);
-struct cls_rule *classifier_replace(struct classifier *, struct cls_rule *);
-void classifier_remove(struct classifier *, struct cls_rule *);
-struct cls_rule *classifier_lookup(const struct classifier *,
+bool classifier_is_empty(const struct classifier *cls)
+    OVS_REQ_RDLOCK(cls->rwlock);
+int classifier_count(const struct classifier *cls)
+    OVS_REQ_RDLOCK(cls->rwlock);
+void classifier_insert(struct classifier *cls, struct cls_rule *)
+    OVS_REQ_WRLOCK(cls->rwlock);
+struct cls_rule *classifier_replace(struct classifier *cls, struct cls_rule *)
+    OVS_REQ_WRLOCK(cls->rwlock);
+void classifier_remove(struct classifier *cls, struct cls_rule *)
+    OVS_REQ_WRLOCK(cls->rwlock);
+struct cls_rule *classifier_lookup(const struct classifier *cls,
                                    const struct flow *,
-                                   struct flow_wildcards *);
-bool classifier_rule_overlaps(const struct classifier *,
-                              const struct cls_rule *);
+                                   struct flow_wildcards *)
+    OVS_REQ_RDLOCK(cls->rwlock);
+bool classifier_rule_overlaps(const struct classifier *cls,
+                              const struct cls_rule *)
+    OVS_REQ_RDLOCK(cls->rwlock);
 
 typedef void cls_cb_func(struct cls_rule *, void *aux);
 
-struct cls_rule *classifier_find_rule_exactly(const struct classifier *,
-                                              const struct cls_rule *);
-struct cls_rule *classifier_find_match_exactly(const struct classifier *,
+struct cls_rule *classifier_find_rule_exactly(const struct classifier *cls,
+                                              const struct cls_rule *)
+    OVS_REQ_RDLOCK(cls->rwlock);
+struct cls_rule *classifier_find_match_exactly(const struct classifier *cls,
                                                const struct match *,
-                                               unsigned int priority);
+                                               unsigned int priority)
+    OVS_REQ_RDLOCK(cls->rwlock);
 \f
 /* Iteration. */
 
@@ -117,10 +136,10 @@ struct cls_cursor {
     const struct cls_rule *target;
 };
 
-void cls_cursor_init(struct cls_cursor *, const struct classifier *,
-                     const struct cls_rule *match);
-struct cls_rule *cls_cursor_first(struct cls_cursor *);
-struct cls_rule *cls_cursor_next(struct cls_cursor *, struct cls_rule *);
+void cls_cursor_init(struct cls_cursor *cursor, const struct classifier *cls,
+                     const struct cls_rule *match) OVS_REQ_RDLOCK(cls->rwlock);
+struct cls_rule *cls_cursor_first(struct cls_cursor *cursor);
+struct cls_rule *cls_cursor_next(struct cls_cursor *cursor, struct cls_rule *);
 
 #define CLS_CURSOR_FOR_EACH(RULE, MEMBER, CURSOR)                       \
     for (ASSIGN_CONTAINER(RULE, cls_cursor_first(CURSOR), MEMBER);      \
index 94a2218..2ca81bd 100644 (file)
  *      while the specific MUTEX is held.
  *
  *
+ * On a variable A of mutex type:
+ *
+ *    - OVS_ACQ_BEFORE(B), where B is a mutex or a comma-separated list of
+ *      mutexes, declare that if both A and B are acquired at the same time,
+ *      then A must be acquired before B.  That is, B nests inside A.
+ *
+ *    - OVS_ACQ_AFTER(B) is the opposite of OVS_ACQ_BEFORE(B), that is, it
+ *      declares that A nests inside B.
+ *
+ *
  * On a function, the following attributes apply to mutexes:
  *
  *    - OVS_ACQUIRES(MUTEX) indicate that the function must be called without
@@ -84,6 +94,7 @@
  *    - OVS_LOCKS_EXCLUDED(MUTEX) indicates that the function may only be
  *      called when MUTEX is not held.
  *
+ *
  * The following variants, with the same syntax, apply to reader-writer locks:
  *
  *    mutex                rwlock, for reading  rwlock, for writing
 #define OVS_GUARDED_BY(...) __attribute__((guarded_by(__VA_ARGS__)))
 #define OVS_RELEASES(...) __attribute__((unlock_function(__VA_ARGS__)))
 #define OVS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
+#define OVS_ACQ_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#define OVS_ACQ_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
 #elif __CHECKER__
 /* "sparse" annotations for mutexes and mutex-like constructs.
  *
 #define OVS_GUARDED_BY(...)
 #define OVS_EXCLUDED(...)
 #define OVS_RELEASES(...)   __attribute__((context(MUTEX, 1, 0)))
+#define OVS_ACQ_BEFORE(...)
+#define OVS_ACQ_AFTER(...)
 #define OVS_MACRO_LOCK(...) __context__(MUTEX, 0, 1)
 #define OVS_MACRO_RELEASE(...) __context__(MUTEX, 1, 0)
 #else
 #define OVS_GUARDED_BY(...)
 #define OVS_EXCLUDED(...)
 #define OVS_RELEASES(...)
+#define OVS_ACQ_BEFORE(...)
+#define OVS_ACQ_AFTER(...)
 #define OVS_MACRO_LOCK(...)
 #define OVS_MACRO_RELEASE(...)
 #endif
index de0b663..8269874 100644 (file)
@@ -128,21 +128,21 @@ static struct ovs_mutex mutex;
 static struct list all_lacps__ = LIST_INITIALIZER(&all_lacps__);
 static struct list *const all_lacps OVS_GUARDED_BY(mutex) = &all_lacps__;
 
-static void lacp_update_attached(struct lacp *) OVS_REQ_WRLOCK(mutex);
+static void lacp_update_attached(struct lacp *) OVS_REQUIRES(mutex);
 
-static void slave_destroy(struct slave *) OVS_REQ_WRLOCK(mutex);
-static void slave_set_defaulted(struct slave *) OVS_REQ_WRLOCK(mutex);
-static void slave_set_expired(struct slave *) OVS_REQ_WRLOCK(mutex);
+static void slave_destroy(struct slave *) OVS_REQUIRES(mutex);
+static void slave_set_defaulted(struct slave *) OVS_REQUIRES(mutex);
+static void slave_set_expired(struct slave *) OVS_REQUIRES(mutex);
 static void slave_get_actor(struct slave *, struct lacp_info *actor)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void slave_get_priority(struct slave *, struct lacp_info *priority)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool slave_may_tx(const struct slave *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static struct slave *slave_lookup(const struct lacp *, const void *slave)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 
 static unixctl_cb_func lacp_unixctl_show;
 
@@ -446,7 +446,7 @@ out:
 }
 
 static bool
-slave_may_enable__(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex)
 {
     /* The slave may be enabled if it's attached to an aggregator and its
      * partner is synchronized.*/
@@ -564,7 +564,7 @@ lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
 /* Updates the attached status of all slaves controlled by 'lacp' and sets its
  * negotiated parameter to true if any slaves are attachable. */
 static void
-lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
+lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
 {
     struct slave *lead, *slave;
     struct lacp_info lead_pri;
@@ -613,7 +613,7 @@ lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_destroy(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_destroy(struct slave *slave) OVS_REQUIRES(mutex)
 {
     if (slave) {
         struct lacp *lacp = slave->lacp;
@@ -637,7 +637,7 @@ slave_destroy(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_set_defaulted(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_set_defaulted(struct slave *slave) OVS_REQUIRES(mutex)
 {
     memset(&slave->partner, 0, sizeof slave->partner);
 
@@ -646,7 +646,7 @@ slave_set_defaulted(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_set_expired(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_set_expired(struct slave *slave) OVS_REQUIRES(mutex)
 {
     slave->status = LACP_EXPIRED;
     slave->partner.state |= LACP_STATE_TIME;
@@ -657,7 +657,7 @@ slave_set_expired(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 
 static void
 slave_get_actor(struct slave *slave, struct lacp_info *actor)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     struct lacp *lacp = slave->lacp;
     uint16_t key;
@@ -710,7 +710,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor)
  * link. */
 static void
 slave_get_priority(struct slave *slave, struct lacp_info *priority)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     uint16_t partner_priority, actor_priority;
 
@@ -735,13 +735,13 @@ slave_get_priority(struct slave *slave, struct lacp_info *priority)
 }
 
 static bool
-slave_may_tx(const struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_may_tx(const struct slave *slave) OVS_REQUIRES(mutex)
 {
     return slave->lacp->active || slave->status != LACP_DEFAULTED;
 }
 
 static struct slave *
-slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQ_WRLOCK(mutex)
+slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQUIRES(mutex)
 {
     struct slave *slave;
 
@@ -778,7 +778,7 @@ info_tx_equal(struct lacp_info *a, struct lacp_info *b)
 }
 \f
 static struct lacp *
-lacp_find(const char *name) OVS_REQ_WRLOCK(&mutex)
+lacp_find(const char *name) OVS_REQUIRES(mutex)
 {
     struct lacp *lacp;
 
@@ -828,7 +828,7 @@ ds_put_lacp_state(struct ds *ds, uint8_t state)
 }
 
 static void
-lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQ_WRLOCK(&mutex)
+lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
 {
     struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
     const struct shash_node **sorted_slaves = NULL;
index 5c23d38..b799cb5 100644 (file)
@@ -107,9 +107,6 @@ enum {
     VALID_CARRIER = 1 << 5
 };
 
-/* An AF_INET socket (used for ioctl operations). */
-static int af_inet_sock = -1;
-
 #if defined(__NetBSD__)
 /* AF_LINK socket used for netdev_bsd_get_stats and set_etheraddr */
 static int af_link_sock = -1;
@@ -133,8 +130,6 @@ static int cache_notifier_refcount;
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
 
-static int netdev_bsd_do_ioctl(const char *, struct ifreq *, unsigned long cmd,
-                               const char *cmd_name);
 static void destroy_tap(int fd, const char *name);
 static int get_flags(const struct netdev *, int *flagsp);
 static int set_flags(const char *, int flags);
@@ -181,30 +176,23 @@ netdev_get_kernel_name(const struct netdev *netdev)
 static int
 netdev_bsd_init(void)
 {
+#if defined(__NetBSD__)
     static int status = -1;
 
     if (status >= 0) {  /* already initialized */
         return status;
     }
 
-    af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
-    status = af_inet_sock >= 0 ? 0 : errno;
-    if (status) {
-        VLOG_ERR("failed to create inet socket: %s", ovs_strerror(status));
-        return status;
-    }
-
-#if defined(__NetBSD__)
     af_link_sock = socket(AF_LINK, SOCK_DGRAM, 0);
     status = af_link_sock >= 0 ? 0 : errno;
     if (status) {
         VLOG_ERR("failed to create link socket: %s", ovs_strerror(status));
-        close(af_inet_sock);
-        af_inet_sock = -1;
     }
-#endif /* defined(__NetBSD__) */
 
     return status;
+#else
+    return 0;
+#endif /* defined(__NetBSD__) */
 }
 
 /*
@@ -381,8 +369,8 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name,
     /* Change the name of the tap device */
 #if defined(SIOCSIFNAME)
     ifr.ifr_data = (void *)name;
-    if (ioctl(af_inet_sock, SIOCSIFNAME, &ifr) == -1) {
-        error = errno;
+    error = af_inet_ioctl(SIOCSIFNAME, &ifr);
+    if (error) {
         destroy_tap(netdev->tap_fd, ifr.ifr_name);
         goto error_unref_notifier;
     }
@@ -405,8 +393,8 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name,
     /* Turn device UP */
     ifr_set_flags(&ifr, IFF_UP);
     strncpy(ifr.ifr_name, kernel_name, sizeof ifr.ifr_name);
-    if (ioctl(af_inet_sock, SIOCSIFFLAGS, &ifr) == -1) {
-        error = errno;
+    error = af_inet_ioctl(SIOCSIFFLAGS, &ifr);
+    if (error) {
         destroy_tap(netdev->tap_fd, kernel_name);
         goto error_unref_notifier;
     }
@@ -815,7 +803,7 @@ netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup)
         struct ifreq ifr;
         int error;
 
-        error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr,
+        error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
                                     SIOCGIFMTU, "SIOCGIFMTU");
         if (error) {
             return error;
@@ -844,15 +832,17 @@ netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier)
 
     if (!(netdev->cache_valid & VALID_CARRIER)) {
         struct ifmediareq ifmr;
+        int error;
 
         memset(&ifmr, 0, sizeof(ifmr));
         strncpy(ifmr.ifm_name, netdev_get_kernel_name(netdev_),
                 sizeof ifmr.ifm_name);
 
-        if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) {
+        error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
+        if (error) {
             VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
-                        netdev_get_name(netdev_), ovs_strerror(errno));
-            return errno;
+                        netdev_get_name(netdev_), ovs_strerror(error));
+            return error;
         }
 
         netdev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE;
@@ -1057,10 +1047,11 @@ netdev_bsd_get_features(const struct netdev *netdev,
     /* We make two SIOCGIFMEDIA ioctl calls.  The first to determine the
      * number of supported modes, and a second with a buffer to retrieve
      * them. */
-    if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) {
+    error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
+    if (error) {
         VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
-                    netdev_get_name(netdev), ovs_strerror(errno));
-        return errno;
+                    netdev_get_name(netdev), ovs_strerror(error));
+        return error;
     }
 
     media_list = xcalloc(ifmr.ifm_count, sizeof(int));
@@ -1073,10 +1064,10 @@ netdev_bsd_get_features(const struct netdev *netdev,
         goto cleanup;
     }
 
-    if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) {
+    error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
+    if (error) {
         VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
-                    netdev_get_name(netdev), ovs_strerror(errno));
-        error = errno;
+                    netdev_get_name(netdev), ovs_strerror(error));
         goto cleanup;
     }
 
@@ -1117,7 +1108,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4,
         int error;
 
         ifr.ifr_addr.sa_family = AF_INET;
-        error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr,
+        error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
                                     SIOCGIFADDR, "SIOCGIFADDR");
         if (error) {
             return error;
@@ -1125,7 +1116,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4,
 
         sin = (struct sockaddr_in *) &ifr.ifr_addr;
         netdev->in4 = sin->sin_addr;
-        error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr,
+        error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
                                     SIOCGIFNETMASK, "SIOCGIFNETMASK");
         if (error) {
             return error;
@@ -1348,7 +1339,7 @@ do_set_addr(struct netdev *netdev,
 {
     struct ifreq ifr;
     make_in4_sockaddr(&ifr.ifr_addr, addr);
-    return netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev), &ifr, ioctl_nr,
+    return af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev), &ifr, ioctl_nr,
                                ioctl_name);
 }
 
@@ -1534,7 +1525,7 @@ destroy_tap(int fd, const char *name)
     close(fd);
     strcpy(ifr.ifr_name, name);
     /* XXX What to do if this call fails? */
-    ioctl(af_inet_sock, SIOCIFDESTROY, &ifr);
+    af_inet_ioctl(SIOCIFDESTROY, &ifr);
 }
 
 static int
@@ -1543,7 +1534,7 @@ get_flags(const struct netdev *netdev, int *flags)
     struct ifreq ifr;
     int error;
 
-    error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev), &ifr,
+    error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev), &ifr,
                                 SIOCGIFFLAGS, "SIOCGIFFLAGS");
 
     *flags = ifr_get_flags(&ifr);
@@ -1558,7 +1549,7 @@ set_flags(const char *name, int flags)
 
     ifr_set_flags(&ifr, flags);
 
-    return netdev_bsd_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
+    return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
 }
 
 static int
@@ -1616,16 +1607,18 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED,
 {
 #if defined(__FreeBSD__)
     struct ifreq ifr;
+    int error;
 
     memset(&ifr, 0, sizeof ifr);
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_addr.sa_family = hwaddr_family;
     ifr.ifr_addr.sa_len = hwaddr_len;
     memcpy(ifr.ifr_addr.sa_data, mac, hwaddr_len);
-    if (ioctl(af_inet_sock, SIOCSIFLLADDR, &ifr) < 0) {
+    error = af_inet_ioctl(SIOCSIFLLADDR, &ifr);
+    if (error) {
         VLOG_ERR("ioctl(SIOCSIFLLADDR) on %s device failed: %s",
-                 netdev_name, ovs_strerror(errno));
-        return errno;
+                 netdev_name, ovs_strerror(error));
+        return error;
     }
     return 0;
 #elif defined(__NetBSD__)
@@ -1683,19 +1676,6 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED,
 #endif
 }
 
-static int
-netdev_bsd_do_ioctl(const char *name, struct ifreq *ifr, unsigned long cmd,
-                    const char *cmd_name)
-{
-    strncpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
-    if (ioctl(af_inet_sock, cmd, ifr) == -1) {
-        VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
-                    ovs_strerror(errno));
-        return errno;
-    }
-    return 0;
-}
-
 static int
 ifr_get_flags(const struct ifreq *ifr)
 {
index e7dfe9f..dc3ddf8 100644 (file)
@@ -60,6 +60,8 @@ struct netdev_dummy {
     struct list rxes;           /* List of child "netdev_rx_dummy"s. */
 };
 
+static const struct netdev_class dummy_class;
+
 /* Max 'recv_queue_len' in struct netdev_dummy. */
 #define NETDEV_DUMMY_MAX_QUEUE 100
 
@@ -71,8 +73,6 @@ struct netdev_rx_dummy {
     bool listening;
 };
 
-static struct shash dummy_netdevs = SHASH_INITIALIZER(&dummy_netdevs);
-
 static const struct netdev_rx_class netdev_rx_dummy_class;
 
 static unixctl_cb_func netdev_dummy_set_admin_state;
@@ -106,8 +106,11 @@ netdev_rx_dummy_cast(const struct netdev_rx *rx)
 static void
 netdev_dummy_run(void)
 {
+    struct shash dummy_netdevs;
     struct shash_node *node;
 
+    shash_init(&dummy_netdevs);
+    netdev_get_devices(&dummy_class, &dummy_netdevs);
     SHASH_FOR_EACH (node, &dummy_netdevs) {
         struct netdev_dummy *dev = node->data;
         size_t i;
@@ -202,7 +205,10 @@ netdev_dummy_run(void)
                 dev->streams[i] = dev->streams[--dev->n_streams];
             }
         }
+
+        netdev_close(&dev->up);
     }
+    shash_destroy(&dummy_netdevs);
 }
 
 static void
@@ -216,8 +222,11 @@ dummy_stream_close(struct dummy_stream *s)
 static void
 netdev_dummy_wait(void)
 {
+    struct shash dummy_netdevs;
     struct shash_node *node;
 
+    shash_init(&dummy_netdevs);
+    netdev_get_devices(&dummy_class, &dummy_netdevs);
     SHASH_FOR_EACH (node, &dummy_netdevs) {
         struct netdev_dummy *dev = node->data;
         size_t i;
@@ -234,7 +243,9 @@ netdev_dummy_wait(void)
             }
             stream_recv_wait(s->stream);
         }
+        netdev_close(&dev->up);
     }
+    shash_destroy(&dummy_netdevs);
 }
 
 static int
@@ -265,8 +276,6 @@ netdev_dummy_create(const struct netdev_class *class, const char *name,
 
     list_init(&netdev->rxes);
 
-    shash_add(&dummy_netdevs, name, netdev);
-
     *netdevp = &netdev->up;
 
     return 0;
@@ -278,8 +287,6 @@ netdev_dummy_destroy(struct netdev *netdev_)
     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
     size_t i;
 
-    shash_find_and_delete(&dummy_netdevs,
-                          netdev_get_name(netdev_));
     pstream_close(netdev->pstream);
     for (i = 0; i < netdev->n_streams; i++) {
         dummy_stream_close(&netdev->streams[i]);
@@ -677,13 +684,15 @@ netdev_dummy_receive(struct unixctl_conn *conn,
                      int argc, const char *argv[], void *aux OVS_UNUSED)
 {
     struct netdev_dummy *dummy_dev;
+    struct netdev *netdev;
     int i;
 
-    dummy_dev = shash_find_data(&dummy_netdevs, argv[1]);
-    if (!dummy_dev) {
+    netdev = netdev_from_name(argv[1]);
+    if (!netdev || !is_dummy_class(netdev->netdev_class)) {
         unixctl_command_reply_error(conn, "no such dummy netdev");
-        return;
+        goto exit;
     }
+    dummy_dev = netdev_dummy_cast(netdev);
 
     for (i = 2; i < argc; i++) {
         struct ofpbuf *packet;
@@ -691,7 +700,7 @@ netdev_dummy_receive(struct unixctl_conn *conn,
         packet = eth_from_packet_or_flow(argv[i]);
         if (!packet) {
             unixctl_command_reply_error(conn, "bad packet syntax");
-            return;
+            goto exit;
         }
 
         dummy_dev->stats.rx_packets++;
@@ -701,6 +710,9 @@ netdev_dummy_receive(struct unixctl_conn *conn,
     }
 
     unixctl_command_reply(conn, NULL);
+
+exit:
+    netdev_close(netdev);
 }
 
 static void
@@ -731,21 +743,29 @@ netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc,
     }
 
     if (argc > 2) {
-        struct netdev_dummy *dummy_dev;
+        struct netdev *netdev = netdev_from_name(argv[1]);
+        if (netdev && is_dummy_class(netdev->netdev_class)) {
+            struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
 
-        dummy_dev = shash_find_data(&dummy_netdevs, argv[1]);
-        if (dummy_dev) {
             netdev_dummy_set_admin_state__(dummy_dev, up);
+            netdev_close(netdev);
         } else {
             unixctl_command_reply_error(conn, "Unknown Dummy Interface");
+            netdev_close(netdev);
             return;
         }
     } else {
+        struct shash dummy_netdevs;
         struct shash_node *node;
 
+        shash_init(&dummy_netdevs);
+        netdev_get_devices(&dummy_class, &dummy_netdevs);
         SHASH_FOR_EACH (node, &dummy_netdevs) {
-            netdev_dummy_set_admin_state__(node->data, up);
+            struct netdev *netdev = node->data;
+            netdev_dummy_set_admin_state__(netdev_dummy_cast(netdev), up);
+            netdev_close(netdev);
         }
+        shash_destroy(&dummy_netdevs);
     }
     unixctl_command_reply(conn, "OK");
 }
index c59f590..9306100 100644 (file)
@@ -400,19 +400,14 @@ struct netdev_rx_linux {
 
 static const struct netdev_rx_class netdev_rx_linux_class;
 
-/* Sockets used for ioctl operations. */
-static int af_inet_sock = -1;   /* AF_INET, SOCK_DGRAM. */
-
 /* This is set pretty low because we probably won't learn anything from the
  * additional log messages. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
 
-static int netdev_linux_init(void);
+static void netdev_linux_run(void);
 
 static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
                                    int cmd, const char *cmd_name);
-static int netdev_linux_do_ioctl(const char *name, struct ifreq *, int cmd,
-                                 const char *cmd_name);
 static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *,
                                  int cmd, const char *cmd_name);
 static int get_flags(const struct netdev *, unsigned int *flags);
@@ -433,7 +428,7 @@ static void netdev_linux_miimon_wait(void);
 static bool
 is_netdev_linux_class(const struct netdev_class *netdev_class)
 {
-    return netdev_class->init == netdev_linux_init;
+    return netdev_class->run == netdev_linux_run;
 }
 
 static bool
@@ -457,21 +452,6 @@ netdev_rx_linux_cast(const struct netdev_rx *rx)
     return CONTAINER_OF(rx, struct netdev_rx_linux, up);
 }
 \f
-static int
-netdev_linux_init(void)
-{
-    static int status = -1;
-    if (status < 0) {
-        /* Create AF_INET socket. */
-        af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
-        status = af_inet_sock >= 0 ? 0 : errno;
-        if (status) {
-            VLOG_ERR("failed to create inet socket: %s", ovs_strerror(status));
-        }
-    }
-    return status;
-}
-
 static void
 netdev_linux_run(void)
 {
@@ -721,13 +701,15 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
         struct sockaddr_ll sll;
         int ifindex;
         /* Result of tcpdump -dd inbound */
-        static struct sock_filter filt[] = {
+        static const struct sock_filter filt[] = {
             { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */
             { 0x15, 0, 1, 0x00000004 }, /* jeq #4     jt 2  jf 3 */
             { 0x6, 0, 0, 0x00000000 },  /* ret #0 */
             { 0x6, 0, 0, 0x0000ffff }   /* ret #65535 */
         };
-        static struct sock_fprog fprog = { ARRAY_SIZE(filt), filt };
+        static const struct sock_fprog fprog = {
+            ARRAY_SIZE(filt), (struct sock_filter *) filt
+        };
 
         /* Create file descriptor. */
         fd = socket(PF_PACKET, SOCK_RAW, 0);
@@ -766,7 +748,7 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
                            sizeof fprog);
         if (error) {
             error = errno;
-            VLOG_ERR("%s: failed attach filter (%s)",
+            VLOG_ERR("%s: failed to attach filter (%s)",
                      netdev_get_name(netdev_), ovs_strerror(error));
             goto error;
         }
@@ -834,8 +816,8 @@ netdev_rx_linux_drain(struct netdev_rx *rx_)
     struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
     if (rx->is_tap) {
         struct ifreq ifr;
-        int error = netdev_linux_do_ioctl(netdev_rx_get_name(rx_), &ifr,
-                                          SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
+        int error = af_inet_ifreq_ioctl(netdev_rx_get_name(rx_), &ifr,
+                                        SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
         if (error) {
             return error;
         }
@@ -1019,8 +1001,8 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
         struct ifreq ifr;
         int error;
 
-        error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
-                                      SIOCGIFMTU, "SIOCGIFMTU");
+        error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
+                                    SIOCGIFMTU, "SIOCGIFMTU");
 
         netdev->netdev_mtu_error = error;
         netdev->mtu = ifr.ifr_mtu;
@@ -1053,8 +1035,8 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu)
         netdev->cache_valid &= ~VALID_MTU;
     }
     ifr.ifr_mtu = mtu;
-    error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
-                                  SIOCSIFMTU, "SIOCSIFMTU");
+    error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
+                                SIOCSIFMTU, "SIOCSIFMTU");
     if (!error || error == ENODEV) {
         netdev->netdev_mtu_error = error;
         netdev->mtu = ifr.ifr_mtu;
@@ -1103,7 +1085,7 @@ netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name,
 
     memset(&ifr, 0, sizeof ifr);
     memcpy(&ifr.ifr_data, data, sizeof *data);
-    error = netdev_linux_do_ioctl(name, &ifr, cmd, cmd_name);
+    error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name);
     memcpy(data, &ifr.ifr_data, sizeof *data);
 
     return error;
@@ -2191,11 +2173,10 @@ do_set_addr(struct netdev *netdev,
             int ioctl_nr, const char *ioctl_name, struct in_addr addr)
 {
     struct ifreq ifr;
-    ovs_strzcpy(ifr.ifr_name, netdev_get_name(netdev), sizeof ifr.ifr_name);
-    make_in4_sockaddr(&ifr.ifr_addr, addr);
 
-    return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
-                                 ioctl_name);
+    make_in4_sockaddr(&ifr.ifr_addr, addr);
+    return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
+                               ioctl_name);
 }
 
 /* Adds 'router' as a default IP gateway. */
@@ -2211,7 +2192,7 @@ netdev_linux_add_router(struct netdev *netdev OVS_UNUSED, struct in_addr router)
     make_in4_sockaddr(&rt.rt_gateway, router);
     make_in4_sockaddr(&rt.rt_genmask, any);
     rt.rt_flags = RTF_UP | RTF_GATEWAY;
-    error = ioctl(af_inet_sock, SIOCADDRT, &rt) < 0 ? errno : 0;
+    error = af_inet_ioctl(SIOCADDRT, &rt);
     if (error) {
         VLOG_WARN("ioctl(SIOCADDRT): %s", ovs_strerror(error));
     }
@@ -2337,7 +2318,7 @@ netdev_linux_arp_lookup(const struct netdev *netdev,
     r.arp_flags = 0;
     ovs_strzcpy(r.arp_dev, netdev_get_name(netdev), sizeof r.arp_dev);
     COVERAGE_INC(netdev_arp_lookup);
-    retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0;
+    retval = af_inet_ioctl(SIOCGARP, &r);
     if (!retval) {
         memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN);
     } else if (retval != ENXIO) {
@@ -2403,7 +2384,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
 {                                                               \
     NAME,                                                       \
                                                                 \
-    netdev_linux_init,                                          \
+    NULL,                                                       \
     netdev_linux_run,                                           \
     netdev_linux_wait,                                          \
                                                                 \
@@ -4193,14 +4174,6 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes)
 \f
 /* Linux-only functions declared in netdev-linux.h  */
 
-/* Returns a fd for an AF_INET socket or a negative errno value. */
-int
-netdev_linux_get_af_inet_sock(void)
-{
-    int error = netdev_linux_init();
-    return error ? -error : af_inet_sock;
-}
-
 /* Modifies the 'flag' bit in ethtool's flags field for 'netdev'.  If
  * 'enable' is true, the bit is set.  Otherwise, it is cleared. */
 int
@@ -4393,8 +4366,7 @@ get_flags(const struct netdev *dev, unsigned int *flags)
     int error;
 
     *flags = 0;
-    error = netdev_linux_do_ioctl(dev->name, &ifr, SIOCGIFFLAGS,
-                                  "SIOCGIFFLAGS");
+    error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS");
     if (!error) {
         *flags = ifr.ifr_flags;
     }
@@ -4407,20 +4379,23 @@ set_flags(const char *name, unsigned int flags)
     struct ifreq ifr;
 
     ifr.ifr_flags = flags;
-    return netdev_linux_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
+    return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
 }
 
 static int
 do_get_ifindex(const char *netdev_name)
 {
     struct ifreq ifr;
+    int error;
 
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     COVERAGE_INC(netdev_get_ifindex);
-    if (ioctl(af_inet_sock, SIOCGIFINDEX, &ifr) < 0) {
+
+    error = af_inet_ioctl(SIOCGIFINDEX, &ifr);
+    if (error) {
         VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s",
-                     netdev_name, ovs_strerror(errno));
-        return -errno;
+                     netdev_name, ovs_strerror(error));
+        return -error;
     }
     return ifr.ifr_ifindex;
 }
@@ -4452,18 +4427,20 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
 {
     struct ifreq ifr;
     int hwaddr_family;
+    int error;
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     COVERAGE_INC(netdev_get_hwaddr);
-    if (ioctl(af_inet_sock, SIOCGIFHWADDR, &ifr) < 0) {
+    error = af_inet_ioctl(SIOCGIFHWADDR, &ifr);
+    if (error) {
         /* ENODEV probably means that a vif disappeared asynchronously and
          * hasn't been removed from the database yet, so reduce the log level
          * to INFO for that case. */
-        VLOG(errno == ENODEV ? VLL_INFO : VLL_ERR,
+        VLOG(error == ENODEV ? VLL_INFO : VLL_ERR,
              "ioctl(SIOCGIFHWADDR) on %s device failed: %s",
-             netdev_name, ovs_strerror(errno));
-        return errno;
+             netdev_name, ovs_strerror(error));
+        return error;
     }
     hwaddr_family = ifr.ifr_hwaddr.sa_family;
     if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
@@ -4479,18 +4456,19 @@ set_etheraddr(const char *netdev_name,
               const uint8_t mac[ETH_ADDR_LEN])
 {
     struct ifreq ifr;
+    int error;
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
     memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN);
     COVERAGE_INC(netdev_set_hwaddr);
-    if (ioctl(af_inet_sock, SIOCSIFHWADDR, &ifr) < 0) {
+    error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
+    if (error) {
         VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s",
-                 netdev_name, ovs_strerror(errno));
-        return errno;
+                 netdev_name, ovs_strerror(error));
     }
-    return 0;
+    return error;
 }
 
 static int
@@ -4498,37 +4476,24 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd,
                         int cmd, const char *cmd_name)
 {
     struct ifreq ifr;
+    int error;
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
     ifr.ifr_data = (caddr_t) ecmd;
 
     ecmd->cmd = cmd;
-    if (ioctl(af_inet_sock, SIOCETHTOOL, &ifr) == 0) {
-        return 0;
-    } else {
-        if (errno != EOPNOTSUPP) {
+    error = af_inet_ioctl(SIOCETHTOOL, &ifr);
+    if (error) {
+        if (error != EOPNOTSUPP) {
             VLOG_WARN_RL(&rl, "ethtool command %s on network device %s "
-                         "failed: %s", cmd_name, name, ovs_strerror(errno));
+                         "failed: %s", cmd_name, name, ovs_strerror(error));
         } else {
             /* The device doesn't support this operation.  That's pretty
              * common, so there's no point in logging anything. */
         }
-        return errno;
-    }
-}
-
-static int
-netdev_linux_do_ioctl(const char *name, struct ifreq *ifr, int cmd,
-                      const char *cmd_name)
-{
-    ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
-    if (ioctl(af_inet_sock, cmd, ifr) == -1) {
-        VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
-                     ovs_strerror(errno));
-        return errno;
     }
-    return 0;
+    return error;
 }
 
 static int
@@ -4539,7 +4504,7 @@ netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip,
     int error;
 
     ifr.ifr_addr.sa_family = AF_INET;
-    error = netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, cmd, cmd_name);
+    error = af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, cmd, cmd_name);
     if (!error) {
         const struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *,
                                                      &ifr.ifr_addr);
index 7874dd6..0c61bc9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Nicira, Inc.
+ * Copyright (c) 2011, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,5 @@ struct netdev;
 
 int netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag,
                                   const char *flag_name, bool enable);
-int netdev_linux_get_af_inet_sock(void);
 
 #endif /* netdev-linux.h */
index 21311f7..f3348c0 100644 (file)
@@ -342,6 +342,8 @@ struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
 
 /* Abstract packet-in message. */
 struct ofputil_packet_in {
+    struct list list_node; /* For queueing packet_ins. */
+
     const void *packet;
     size_t packet_len;
 
index 4d64b92..c156070 100644 (file)
@@ -126,8 +126,11 @@ XPTHREAD_FUNC1(pthread_cond_destroy, pthread_cond_t *);
 XPTHREAD_FUNC1(pthread_cond_signal, pthread_cond_t *);
 XPTHREAD_FUNC1(pthread_cond_broadcast, pthread_cond_t *);
 
+XPTHREAD_FUNC2(pthread_join, pthread_t, void **);
+
 typedef void destructor_func(void *);
 XPTHREAD_FUNC2(pthread_key_create, pthread_key_t *, destructor_func *);
+XPTHREAD_FUNC2(pthread_setspecific, pthread_key_t, const void *);
 
 void
 ovs_mutex_init(const struct ovs_mutex *l_, int type)
@@ -168,18 +171,49 @@ ovs_mutex_cond_wait(pthread_cond_t *cond, const struct ovs_mutex *mutex_)
         ovs_abort(error, "pthread_cond_wait failed");
     }
 }
+\f
+DEFINE_EXTERN_PER_THREAD_DATA(ovsthread_id, 0);
+
+struct ovsthread_aux {
+    void *(*start)(void *);
+    void *arg;
+};
+
+static void *
+ovsthread_wrapper(void *aux_)
+{
+    static atomic_uint next_id = ATOMIC_VAR_INIT(1);
+
+    struct ovsthread_aux *auxp = aux_;
+    struct ovsthread_aux aux;
+    unsigned int id;
+
+    atomic_add(&next_id, 1, &id);
+    *ovsthread_id_get() = id;
+
+    aux = *auxp;
+    free(auxp);
+
+    return aux.start(aux.arg);
+}
 
 void
 xpthread_create(pthread_t *threadp, pthread_attr_t *attr,
                 void *(*start)(void *), void *arg)
 {
+    struct ovsthread_aux *aux;
     pthread_t thread;
     int error;
 
     forbid_forking("multiple threads exist");
     multithreaded = true;
 
-    error = pthread_create(threadp ? threadp : &thread, attr, start, arg);
+    aux = xmalloc(sizeof *aux);
+    aux->start = start;
+    aux->arg = arg;
+
+    error = pthread_create(threadp ? threadp : &thread, attr,
+                           ovsthread_wrapper, aux);
     if (error) {
         ovs_abort(error, "pthread_create failed");
     }
index 9b8eeef..3547686 100644 (file)
@@ -116,7 +116,7 @@ void ovs_rwlock_unlock(const struct ovs_rwlock *rwlock) OVS_RELEASES(rwlock);
 void ovs_rwlock_wrlock_at(const struct ovs_rwlock *rwlock, const char *where)
     OVS_ACQ_WRLOCK(rwlock);
 #define ovs_rwlock_wrlock(rwlock) \
-        ovs_rwlock_wrlock_at(rwlock, SOURCE_LOCATOR);
+        ovs_rwlock_wrlock_at(rwlock, SOURCE_LOCATOR)
 
 int ovs_rwlock_trywrlock_at(const struct ovs_rwlock *rwlock, const char *where)
     OVS_TRY_WRLOCK(0, rwlock);
@@ -126,7 +126,7 @@ int ovs_rwlock_trywrlock_at(const struct ovs_rwlock *rwlock, const char *where)
 void ovs_rwlock_rdlock_at(const struct ovs_rwlock *rwlock, const char *where)
     OVS_ACQ_RDLOCK(rwlock);
 #define ovs_rwlock_rdlock(rwlock) \
-        ovs_rwlock_rdlock_at(rwlock, SOURCE_LOCATOR);
+        ovs_rwlock_rdlock_at(rwlock, SOURCE_LOCATOR)
 
 int ovs_rwlock_tryrdlock_at(const struct ovs_rwlock *rwlock, const char *where)
     OVS_TRY_RDLOCK(0, rwlock);
@@ -153,8 +153,10 @@ void xpthread_cond_broadcast(pthread_cond_t *);
 #endif
 
 void xpthread_key_create(pthread_key_t *, void (*destructor)(void *));
+void xpthread_setspecific(pthread_key_t, const void *);
 
 void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
+void xpthread_join(pthread_t, void **);
 \f
 /* Per-thread data.
  *
@@ -192,7 +194,15 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
  * cross-thread access?     yes                no                yes
  */
 
-/* DEFINE_PER_THREAD_DATA(TYPE, NAME, INITIALIZER).
+/* For static data, use this macro in a source file:
+ *
+ *    DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, INITIALIZER).
+ *
+ * For global data, "declare" the data in the header and "define" it in
+ * the source file, with:
+ *
+ *    DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME).
+ *    DEFINE_EXTERN_PER_THREAD_DATA(NAME, INITIALIZER).
  *
  * One should prefer to use POSIX per-thread data, via pthread_key_t, when its
  * performance is acceptable, because of its portability (see the table above).
@@ -230,23 +240,40 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
 #error
 #endif
 
-#define DEFINE_PER_THREAD_DATA(TYPE, NAME, ...)                 \
-    typedef TYPE NAME##_type;                                   \
-    static thread_local NAME##_type NAME##_var = __VA_ARGS__;   \
-                                                                \
-    static NAME##_type *                                        \
-    NAME##_get_unsafe(void)                                     \
-    {                                                           \
-        return &NAME##_var;                                     \
-    }                                                           \
-                                                                \
-    static NAME##_type *                                        \
-    NAME##_get(void)                                            \
-    {                                                           \
-        return NAME##_get_unsafe();                             \
+#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...)                  \
+    typedef TYPE NAME##_type;                                           \
+                                                                        \
+    static NAME##_type *                                                \
+    NAME##_get_unsafe(void)                                             \
+    {                                                                   \
+        static thread_local NAME##_type var = __VA_ARGS__;              \
+        return &var;                                                    \
+    }                                                                   \
+                                                                        \
+    static NAME##_type *                                                \
+    NAME##_get(void)                                                    \
+    {                                                                   \
+        return NAME##_get_unsafe();                                     \
+    }
+#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME)                      \
+    typedef TYPE NAME##_type;                                           \
+    extern thread_local NAME##_type NAME##_var;                         \
+                                                                        \
+    static inline NAME##_type *                                         \
+    NAME##_get_unsafe(void)                                             \
+    {                                                                   \
+        return &NAME##_var;                                             \
+    }                                                                   \
+                                                                        \
+    static inline NAME##_type *                                         \
+    NAME##_get(void)                                                    \
+    {                                                                   \
+        return NAME##_get_unsafe();                                     \
     }
+#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...)         \
+    thread_local NAME##_type NAME##_var = __VA_ARGS__;
 #else  /* no C implementation support for thread-local storage  */
-#define DEFINE_PER_THREAD_DATA(TYPE, NAME, ...)                         \
+#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...)                  \
     typedef TYPE NAME##_type;                                           \
     static pthread_key_t NAME##_key;                                    \
                                                                         \
@@ -277,7 +304,44 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
                                                                         \
             value = xmalloc(sizeof *value);                             \
             *value = initial_value;                                     \
-            pthread_setspecific(NAME##_key, value);                     \
+            xpthread_setspecific(NAME##_key, value);                    \
+        }                                                               \
+        return value;                                                   \
+    }
+#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME)                      \
+    typedef TYPE NAME##_type;                                           \
+    static pthread_key_t NAME##_key;                                    \
+                                                                        \
+    static inline NAME##_type *                                         \
+    NAME##_get_unsafe(void)                                             \
+    {                                                                   \
+        return pthread_getspecific(NAME##_key);                         \
+    }                                                                   \
+                                                                        \
+    NAME##_type *NAME##_get(void);
+#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...)                        \
+    static void                                                         \
+    NAME##_once_init(void)                                              \
+    {                                                                   \
+        if (pthread_key_create(&NAME##_key, free)) {                    \
+            abort();                                                    \
+        }                                                               \
+    }                                                                   \
+                                                                        \
+    NAME##_type *                                                       \
+    NAME##_get(void)                                                    \
+    {                                                                   \
+        static pthread_once_t once = PTHREAD_ONCE_INIT;                 \
+        NAME##_type *value;                                             \
+                                                                        \
+        pthread_once(&once, NAME##_once_init);                          \
+        value = NAME##_get_unsafe();                                    \
+        if (!value) {                                                   \
+            static const NAME##_type initial_value = __VA_ARGS__;       \
+                                                                        \
+            value = xmalloc(sizeof *value);                             \
+            *value = initial_value;                                     \
+            xpthread_setspecific(NAME##_key, value);                    \
         }                                                               \
         return value;                                                   \
     }
@@ -348,7 +412,7 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
     NAME##_set_unsafe(TYPE value)                       \
     {                                                   \
         TYPE old_value = NAME##_get_unsafe();           \
-        pthread_setspecific(NAME##_key, value);         \
+        xpthread_setspecific(NAME##_key, value);        \
         return old_value;                               \
     }                                                   \
                                                         \
@@ -438,6 +502,23 @@ ovsthread_once_start(struct ovsthread_once *once)
     ((ONCE)->done ? false : ({ OVS_MACRO_LOCK((&ONCE->mutex)); true; }))
 #endif
 \f
+/* Thread ID.
+ *
+ * pthread_t isn't so nice for some purposes.  Its size and representation are
+ * implementation dependent, which means that there is no way to hash it.
+ * This thread ID avoids the problem.
+ */
+
+DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, ovsthread_id);
+
+/* Returns a per-thread identifier unique within the lifetime of the
+ * process. */
+static inline unsigned int
+ovsthread_id_self(void)
+{
+    return *ovsthread_id_get();
+}
+\f
 void assert_single_threaded_at(const char *where);
 #define assert_single_threaded() assert_single_threaded_at(SOURCE_LOCATOR)
 
index 0f45d98..5f9b9cd 100644 (file)
@@ -275,7 +275,7 @@ poll_loop(void)
     loop = pthread_getspecific(key);
     if (!loop) {
         loop = xzalloc(sizeof *loop);
-        pthread_setspecific(key, loop);
+        xpthread_setspecific(key, loop);
     }
     return loop;
 }
index da29fd0..d6f7d9d 100644 (file)
@@ -39,7 +39,7 @@
  * cryptographic-quality randomness. */
 
 /* Current random state. */
-DEFINE_PER_THREAD_DATA(uint32_t, seed, 0);
+DEFINE_STATIC_PER_THREAD_DATA(uint32_t, seed, 0);
 
 static uint32_t random_next(void);
 
index 1d0cede..7f34ea2 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -1353,3 +1354,42 @@ error:
     *n_fdsp = 0;
     return EPROTO;
 }
+
+/* Calls ioctl() on an AF_INET sock, passing the specified 'command' and
+ * 'arg'.  Returns 0 if successful, otherwise a positive errno value. */
+int
+af_inet_ioctl(unsigned long int command, const void *arg)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    static int sock;
+
+    if (ovsthread_once_start(&once)) {
+        sock = socket(AF_INET, SOCK_DGRAM, 0);
+        if (sock < 0) {
+            sock = -errno;
+            VLOG_ERR("failed to create inet socket: %s", ovs_strerror(errno));
+        }
+        ovsthread_once_done(&once);
+    }
+
+    return (sock < 0 ? -sock
+            : ioctl(sock, command, arg) == -1 ? errno
+            : 0);
+}
+
+int
+af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
+                    const char *cmd_name)
+{
+    int error;
+
+    ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
+    error = af_inet_ioctl(cmd, ifr);
+    if (error) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
+        VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
+                    ovs_strerror(error));
+    }
+    return error;
+}
+
index 96aad5d..670eeb3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -97,4 +97,10 @@ int recv_data_and_fds(int sock,
                       void *data, size_t size,
                       int fds[SOUTIL_MAX_FDS], size_t *n_fdsp);
 
+/* Helpers for calling ioctl() on an AF_INET socket. */
+struct ifreq;
+int af_inet_ioctl(unsigned long int command, const void *arg);
+int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
+                        unsigned long int cmd, const char *cmd_name);
+
 #endif /* socket-util.h */
index 2ff9df7..d570be9 100644 (file)
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -146,7 +146,7 @@ struct stp {
 
 static struct ovs_mutex mutex;
 static struct list all_stps__ = LIST_INITIALIZER(&all_stps__);
-static struct list *const all_stps OVS_GUARDED_BY(&mutex) = &all_stps__;
+static struct list *const all_stps OVS_GUARDED_BY(mutex) = &all_stps__;
 
 #define FOR_EACH_ENABLED_PORT(PORT, STP)                        \
     for ((PORT) = stp_next_enabled_port((STP), (STP)->ports);   \
@@ -154,7 +154,7 @@ static struct list *const all_stps OVS_GUARDED_BY(&mutex) = &all_stps__;
          (PORT) = stp_next_enabled_port((STP), (PORT) + 1))
 static struct stp_port *
 stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
         if (port->state != STP_DISABLED) {
@@ -166,57 +166,57 @@ stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
 
 #define MESSAGE_AGE_INCREMENT 1
 
-static void stp_transmit_config(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+static void stp_transmit_config(struct stp_port *) OVS_REQUIRES(mutex);
 static bool stp_supersedes_port_info(const struct stp_port *,
                                      const struct stp_config_bpdu *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_record_config_information(struct stp_port *,
                                           const struct stp_config_bpdu *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_record_config_timeout_values(struct stp *,
                                              const struct stp_config_bpdu  *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool stp_is_designated_port(const struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_config_bpdu_generation(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_transmit_tcn(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_configuration_update(struct stp *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_config_bpdu_generation(struct stp *) OVS_REQUIRES(mutex);
+static void stp_transmit_tcn(struct stp *) OVS_REQUIRES(mutex);
+static void stp_configuration_update(struct stp *) OVS_REQUIRES(mutex);
 static bool stp_supersedes_root(const struct stp_port *root,
-                                const struct stp_port *) OVS_REQ_WRLOCK(mutex);
-static void stp_root_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_designated_port_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
+                                const struct stp_port *) OVS_REQUIRES(mutex);
+static void stp_root_selection(struct stp *) OVS_REQUIRES(mutex);
+static void stp_designated_port_selection(struct stp *) OVS_REQUIRES(mutex);
 static void stp_become_designated_port(struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_port_state_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_make_forwarding(struct stp_port *) OVS_REQ_WRLOCK(mutex);
-static void stp_make_blocking(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_port_state_selection(struct stp *) OVS_REQUIRES(mutex);
+static void stp_make_forwarding(struct stp_port *) OVS_REQUIRES(mutex);
+static void stp_make_blocking(struct stp_port *) OVS_REQUIRES(mutex);
 static void stp_set_port_state(struct stp_port *, enum stp_state)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_topology_change_detection(struct stp *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_topology_change_detection(struct stp *) OVS_REQUIRES(mutex);
 static void stp_topology_change_acknowledged(struct stp *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_acknowledge_topology_change(struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_received_config_bpdu(struct stp *, struct stp_port *,
                                      const struct stp_config_bpdu *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_received_tcn_bpdu(struct stp *, struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_hello_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_hello_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
 static void stp_message_age_timer_expiry(struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool stp_is_designated_for_some_port(const struct stp *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_forward_delay_timer_expiry(struct stp_port *)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_tcn_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_tcn_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
 static void stp_topology_change_timer_expiry(struct stp *)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_hold_timer_expiry(struct stp_port *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_hold_timer_expiry(struct stp_port *) OVS_REQUIRES(mutex);
 static void stp_initialize_port(struct stp_port *, enum stp_state)
-    OVS_REQ_WRLOCK(mutex);
-static void stp_become_root_bridge(struct stp *) OVS_REQ_WRLOCK(mutex);
-static void stp_update_bridge_timers(struct stp *) OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
+static void stp_become_root_bridge(struct stp *) OVS_REQUIRES(mutex);
+static void stp_update_bridge_timers(struct stp *) OVS_REQUIRES(mutex);
 
 static int clamp(int x, int min, int max);
 static int ms_to_timer(int ms);
@@ -226,7 +226,7 @@ static void stp_stop_timer(struct stp_timer *);
 static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
 
 static void stp_send_bpdu(struct stp_port *, const void *, size_t)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
                             const char *argv[], void *aux);
 
@@ -393,7 +393,7 @@ out:
 
 static void
 set_bridge_id(struct stp *stp, stp_identifier new_bridge_id)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (new_bridge_id != stp->bridge_id) {
         bool root;
@@ -1005,7 +1005,7 @@ stp_port_disable_change_detection(struct stp_port *p)
 }
 \f
 static void
-stp_transmit_config(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     struct stp *stp = p->stp;
     bool root = stp_is_root_bridge(stp);
@@ -1052,7 +1052,7 @@ stp_transmit_config(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 static bool
 stp_supersedes_port_info(const struct stp_port *p,
                          const struct stp_config_bpdu *config)
-     OVS_REQ_WRLOCK(mutex)
+     OVS_REQUIRES(mutex)
 {
     if (ntohll(config->root_id) != p->designated_root) {
         return ntohll(config->root_id) < p->designated_root;
@@ -1069,7 +1069,7 @@ stp_supersedes_port_info(const struct stp_port *p,
 static void
 stp_record_config_information(struct stp_port *p,
                               const struct stp_config_bpdu *config)
-     OVS_REQ_WRLOCK(mutex)
+     OVS_REQUIRES(mutex)
 {
     p->designated_root = ntohll(config->root_id);
     p->designated_cost = ntohl(config->root_path_cost);
@@ -1081,7 +1081,7 @@ stp_record_config_information(struct stp_port *p,
 static void
 stp_record_config_timeout_values(struct stp *stp,
                                  const struct stp_config_bpdu  *config)
-     OVS_REQ_WRLOCK(mutex)
+     OVS_REQUIRES(mutex)
 {
     stp->max_age = ntohs(config->max_age);
     stp->hello_time = ntohs(config->hello_time);
@@ -1090,14 +1090,14 @@ stp_record_config_timeout_values(struct stp *stp,
 }
 
 static bool
-stp_is_designated_port(const struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_is_designated_port(const struct stp_port *p) OVS_REQUIRES(mutex)
 {
     return (p->designated_bridge == p->stp->bridge_id
             && p->designated_port == p->port_id);
 }
 
 static void
-stp_config_bpdu_generation(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_config_bpdu_generation(struct stp *stp) OVS_REQUIRES(mutex)
 {
     struct stp_port *p;
 
@@ -1109,7 +1109,7 @@ stp_config_bpdu_generation(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_transmit_tcn(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_transmit_tcn(struct stp *stp) OVS_REQUIRES(mutex)
 {
     struct stp_port *p = stp->root_port;
     struct stp_tcn_bpdu tcn_bpdu;
@@ -1123,7 +1123,7 @@ stp_transmit_tcn(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_configuration_update(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_configuration_update(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp_root_selection(stp);
     stp_designated_port_selection(stp);
@@ -1131,7 +1131,7 @@ stp_configuration_update(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 
 static bool
 stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     int p_cost = p->designated_cost + p->path_cost;
     int root_cost = root->designated_cost + root->path_cost;
@@ -1150,7 +1150,7 @@ stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
 }
 
 static void
-stp_root_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_root_selection(struct stp *stp) OVS_REQUIRES(mutex)
 {
     struct stp_port *p, *root;
 
@@ -1176,7 +1176,7 @@ stp_root_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_designated_port_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_designated_port_selection(struct stp *stp) OVS_REQUIRES(mutex)
 {
     struct stp_port *p;
 
@@ -1195,7 +1195,7 @@ stp_designated_port_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_become_designated_port(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_become_designated_port(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     struct stp *stp = p->stp;
     p->designated_root = stp->designated_root;
@@ -1205,7 +1205,7 @@ stp_become_designated_port(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_port_state_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_port_state_selection(struct stp *stp) OVS_REQUIRES(mutex)
 {
     struct stp_port *p;
 
@@ -1226,7 +1226,7 @@ stp_port_state_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_make_forwarding(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_make_forwarding(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     if (p->state == STP_BLOCKING) {
         stp_set_port_state(p, STP_LISTENING);
@@ -1235,7 +1235,7 @@ stp_make_forwarding(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_make_blocking(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_make_blocking(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     if (!(p->state & (STP_DISABLED | STP_BLOCKING))) {
         if (p->state & (STP_FORWARDING | STP_LEARNING)) {
@@ -1250,7 +1250,7 @@ stp_make_blocking(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 
 static void
 stp_set_port_state(struct stp_port *p, enum stp_state state)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (state != p->state && !p->state_changed) {
         p->state_changed = true;
@@ -1262,7 +1262,7 @@ stp_set_port_state(struct stp_port *p, enum stp_state state)
 }
 
 static void
-stp_topology_change_detection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_detection(struct stp *stp) OVS_REQUIRES(mutex)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
@@ -1279,14 +1279,14 @@ stp_topology_change_detection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_topology_change_acknowledged(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_acknowledged(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp->topology_change_detected = false;
     stp_stop_timer(&stp->tcn_timer);
 }
 
 static void
-stp_acknowledge_topology_change(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_acknowledge_topology_change(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     p->topology_change_ack = true;
     stp_transmit_config(p);
@@ -1295,7 +1295,7 @@ stp_acknowledge_topology_change(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 static void
 stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
                          const struct stp_config_bpdu *config)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (ntohs(config->message_age) >= ntohs(config->max_age)) {
         VLOG_WARN("%s: received config BPDU with message age (%u) greater "
@@ -1336,7 +1336,7 @@ stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
 
 static void
 stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (p->state != STP_DISABLED) {
         if (stp_is_designated_port(p)) {
@@ -1347,14 +1347,14 @@ stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
 }
 
 static void
-stp_hello_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_hello_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp_config_bpdu_generation(stp);
     stp_start_timer(&stp->hello_timer, 0);
 }
 
 static void
-stp_message_age_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_message_age_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     struct stp *stp = p->stp;
     bool root = stp_is_root_bridge(stp);
@@ -1373,7 +1373,7 @@ stp_message_age_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 }
 
 static bool
-stp_is_designated_for_some_port(const struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_is_designated_for_some_port(const struct stp *stp) OVS_REQUIRES(mutex)
 {
     const struct stp_port *p;
 
@@ -1386,7 +1386,7 @@ stp_is_designated_for_some_port(const struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     if (p->state == STP_LISTENING) {
         stp_set_port_state(p, STP_LEARNING);
@@ -1402,21 +1402,21 @@ stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_tcn_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_tcn_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp_transmit_tcn(stp);
     stp_start_timer(&stp->tcn_timer, 0);
 }
 
 static void
-stp_topology_change_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_topology_change_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp->topology_change_detected = false;
     stp->topology_change = false;
 }
 
 static void
-stp_hold_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
+stp_hold_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
 {
     if (p->config_pending) {
         stp_transmit_config(p);
@@ -1425,7 +1425,7 @@ stp_hold_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
 
 static void
 stp_initialize_port(struct stp_port *p, enum stp_state state)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     ovs_assert(state & (STP_DISABLED | STP_BLOCKING));
     stp_become_designated_port(p);
@@ -1441,7 +1441,7 @@ stp_initialize_port(struct stp_port *p, enum stp_state state)
 }
 
 static void
-stp_become_root_bridge(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_become_root_bridge(struct stp *stp) OVS_REQUIRES(mutex)
 {
     stp->max_age = stp->bridge_max_age;
     stp->hello_time = stp->bridge_hello_time;
@@ -1453,21 +1453,21 @@ stp_become_root_bridge(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-stp_start_timer(struct stp_timer *timer, int value) OVS_REQ_WRLOCK(mutex)
+stp_start_timer(struct stp_timer *timer, int value) OVS_REQUIRES(mutex)
 {
     timer->value = value;
     timer->active = true;
 }
 
 static void
-stp_stop_timer(struct stp_timer *timer) OVS_REQ_WRLOCK(mutex)
+stp_stop_timer(struct stp_timer *timer) OVS_REQUIRES(mutex)
 {
     timer->active = false;
 }
 
 static bool
 stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (timer->active) {
         timer->value += elapsed;
@@ -1502,7 +1502,7 @@ clamp(int x, int min, int max)
 }
 
 static void
-stp_update_bridge_timers(struct stp *stp) OVS_REQ_WRLOCK(mutex)
+stp_update_bridge_timers(struct stp *stp) OVS_REQUIRES(mutex)
 {
     int ht, ma, fd;
 
@@ -1523,7 +1523,7 @@ stp_update_bridge_timers(struct stp *stp) OVS_REQ_WRLOCK(mutex)
 
 static void
 stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     struct eth_header *eth;
     struct llc_header *llc;
@@ -1552,7 +1552,7 @@ stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
 /* Unixctl. */
 
 static struct stp *
-stp_find(const char *name) OVS_REQ_WRLOCK(mutex)
+stp_find(const char *name) OVS_REQUIRES(mutex)
 {
     struct stp *stp;
 
index 05da99e..faf8e7b 100644 (file)
@@ -65,7 +65,7 @@ static long long int deadline = LLONG_MAX;
 
 /* Monotonic time, in milliseconds, at which the last call to time_poll() woke
  * up. */
-DEFINE_PER_THREAD_DATA(long long int, last_wakeup, 0);
+DEFINE_STATIC_PER_THREAD_DATA(long long int, last_wakeup, 0);
 
 static void set_up_timer(void);
 static void set_up_signal(int flags);
index 1751c6f..76c33cd 100644 (file)
@@ -46,7 +46,9 @@ DEFINE_PER_THREAD_MALLOCED_DATA(char *, subprogram_name);
 static char *program_version;
 
 /* Buffer used by ovs_strerror(). */
-DEFINE_PER_THREAD_DATA(struct { char s[128]; }, strerror_buffer, { "" });
+DEFINE_STATIC_PER_THREAD_DATA(struct { char s[128]; },
+                              strerror_buffer,
+                              { "" });
 
 void
 ovs_assert_failure(const char *where, const char *function,
index 5f58f10..282d28c 100644 (file)
@@ -26,6 +26,7 @@
 #include "dummy.h"
 #include "hash.h"
 #include "shash.h"
+#include "socket-util.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(vlandev);
@@ -237,17 +238,11 @@ do_vlan_ioctl(const char *netdev_name, struct vlan_ioctl_args *via,
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
     int error;
-    int sock;
 
     via->cmd = cmd;
     ovs_strlcpy(via->device1, netdev_name, sizeof via->device1);
 
-    sock = netdev_linux_get_af_inet_sock();
-    if (sock < 0) {
-        return -sock;
-    }
-
-    error = ioctl(sock, SIOCSIFVLAN, via) < 0 ? errno : 0;
+    error = af_inet_ioctl(SIOCSIFVLAN, via);
     if (error) {
         VLOG_WARN_RL(&rl, "%s: VLAN ioctl %s failed (%s)",
                      netdev_name, cmd_name, ovs_strerror(error));
index 26d0e6c..ac229b4 100644 (file)
@@ -100,7 +100,7 @@ static struct facility facilities[VLF_N_FACILITIES] = {
 };
 
 /* Sequence number for the message currently being composed. */
-DEFINE_PER_THREAD_DATA(unsigned int, msg_num, 0);
+DEFINE_STATIC_PER_THREAD_DATA(unsigned int, msg_num, 0);
 
 /* VLF_FILE configuration.
  *
index 4264934..1e9ef5b 100644 (file)
@@ -1882,13 +1882,17 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
 
                 fu.event = event;
                 fu.reason = event == NXFME_DELETED ? reason : 0;
-                fu.idle_timeout = rule->idle_timeout;
-                fu.hard_timeout = rule->hard_timeout;
                 fu.table_id = rule->table_id;
                 fu.cookie = rule->flow_cookie;
                 minimatch_expand(&rule->cr.match, &match);
                 fu.match = &match;
                 fu.priority = rule->cr.priority;
+
+                ovs_mutex_lock(&rule->timeout_mutex);
+                fu.idle_timeout = rule->idle_timeout;
+                fu.hard_timeout = rule->hard_timeout;
+                ovs_mutex_unlock(&rule->timeout_mutex);
+
                 if (flags & NXFMF_ACTIONS) {
                     fu.ofpacts = rule->ofpacts;
                     fu.ofpacts_len = rule->ofpacts_len;
index 5f01327..8e8e7a2 100644 (file)
@@ -506,7 +506,7 @@ dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix *di)
 }
 
 static void
-dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQ_WRLOCK(mutex)
+dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQUIRES(mutex)
 {
     struct dpif_ipfix_flow_exporter_map_node *node, *next;
 
index ac80ff9..b387b94 100644 (file)
@@ -146,7 +146,7 @@ sflow_agent_send_packet_cb(void *ds_, SFLAgent *agent OVS_UNUSED,
 
 static struct dpif_sflow_port *
 dpif_sflow_find_port(const struct dpif_sflow *ds, odp_port_t odp_port)
-    OVS_REQ_WRLOCK(&mutex)
+    OVS_REQUIRES(mutex)
 {
     struct dpif_sflow_port *dsp;
 
@@ -162,7 +162,7 @@ dpif_sflow_find_port(const struct dpif_sflow *ds, odp_port_t odp_port)
 static void
 sflow_agent_get_counters(void *ds_, SFLPoller *poller,
                          SFL_COUNTERS_SAMPLE_TYPE *cs)
-    OVS_REQ_WRLOCK(&mutex)
+    OVS_REQUIRES(mutex)
 {
     struct dpif_sflow *ds = ds_;
     SFLCounters_sample_element elem;
@@ -276,7 +276,7 @@ success:
 }
 
 static void
-dpif_sflow_clear__(struct dpif_sflow *ds) OVS_REQ_WRLOCK(mutex)
+dpif_sflow_clear__(struct dpif_sflow *ds) OVS_REQUIRES(mutex)
 {
     if (ds->sflow_agent) {
         sfl_agent_release(ds->sflow_agent);
@@ -382,7 +382,7 @@ dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
 
 static void
 dpif_sflow_add_poller(struct dpif_sflow *ds, struct dpif_sflow_port *dsp)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     SFLPoller *poller = sfl_agent_addPoller(ds->sflow_agent, &dsp->dsi, ds,
                                             sflow_agent_get_counters);
@@ -426,7 +426,7 @@ out:
 
 static void
 dpif_sflow_del_port__(struct dpif_sflow *ds, struct dpif_sflow_port *dsp)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     if (ds->sflow_agent) {
         sfl_agent_removePoller(ds->sflow_agent, &dsp->dsi);
index fb4d0b4..30697ac 100644 (file)
@@ -55,6 +55,8 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate);
  * flow translation. */
 #define MAX_RESUBMIT_RECURSION 64
 
+struct ovs_rwlock xlate_rwlock = OVS_RWLOCK_INITIALIZER;
+
 struct xbridge {
     struct hmap_node hmap_node;   /* Node in global 'xbridges' map. */
     struct ofproto_dpif *ofproto; /* Key in global 'xbridges' map. */
@@ -70,6 +72,10 @@ struct xbridge {
     struct dpif_ipfix *ipfix;     /* Ipfix handle, or null. */
     struct stp *stp;              /* STP or null if disabled. */
 
+    /* Special rules installed by ofproto-dpif. */
+    struct rule_dpif *miss_rule;
+    struct rule_dpif *no_packet_in_rule;
+
     enum ofp_config_flags frag;   /* Fragmentation handling. */
     bool has_netflow;             /* Bridge runs netflow? */
     bool has_in_band;             /* Bridge has in band control? */
@@ -209,8 +215,10 @@ static bool dscp_from_skb_priority(const struct xport *, uint32_t skb_priority,
 
 void
 xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
-                  struct dpif *dpif, const struct mac_learning *ml,
-                  struct stp *stp, const struct mbridge *mbridge,
+                  struct dpif *dpif, struct rule_dpif *miss_rule,
+                  struct rule_dpif *no_packet_in_rule,
+                  const struct mac_learning *ml, struct stp *stp,
+                  const struct mbridge *mbridge,
                   const struct dpif_sflow *sflow,
                   const struct dpif_ipfix *ipfix, enum ofp_config_flags frag,
                   bool forward_bpdu, bool has_in_band, bool has_netflow)
@@ -259,6 +267,8 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
     xbridge->has_in_band = has_in_band;
     xbridge->has_netflow = has_netflow;
     xbridge->frag = frag;
+    xbridge->miss_rule = miss_rule;
+    xbridge->no_packet_in_rule = no_packet_in_rule;
 }
 
 void
@@ -494,6 +504,7 @@ xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
     const struct xport *xport;
     int error = ENODEV;
 
+    ovs_rwlock_rdlock(&xlate_rwlock);
     fitness = odp_flow_key_to_flow(key, key_len, flow);
     if (fitness == ODP_FIT_ERROR) {
         error = EINVAL;
@@ -545,6 +556,7 @@ exit:
     if (fitnessp) {
         *fitnessp = fitness;
     }
+    ovs_rwlock_unlock(&xlate_rwlock);
     return error;
 }
 
@@ -1025,21 +1037,67 @@ is_gratuitous_arp(const struct flow *flow, struct flow_wildcards *wc)
     }
 }
 
-static void
-update_learning_table(const struct xbridge *xbridge,
-                      const struct flow *flow, struct flow_wildcards *wc,
-                      int vlan, struct xbundle *in_xbundle)
+/* Checks whether a MAC learning update is necessary for MAC learning table
+ * 'ml' given that a packet matching 'flow' was received  on 'in_xbundle' in
+ * 'vlan'.
+ *
+ * Most packets processed through the MAC learning table do not actually
+ * change it in any way.  This function requires only a read lock on the MAC
+ * learning table, so it is much cheaper in this common case.
+ *
+ * Keep the code here synchronized with that in update_learning_table__()
+ * below. */
+static bool
+is_mac_learning_update_needed(const struct mac_learning *ml,
+                              const struct flow *flow,
+                              struct flow_wildcards *wc,
+                              int vlan, struct xbundle *in_xbundle)
+    OVS_REQ_RDLOCK(ml->rwlock)
 {
     struct mac_entry *mac;
 
-    /* Don't learn the OFPP_NONE port. */
-    if (in_xbundle == &ofpp_none_bundle) {
-        return;
+    if (!mac_learning_may_learn(ml, flow->dl_src, vlan)) {
+        return false;
     }
 
-    ovs_rwlock_wrlock(&xbridge->ml->rwlock);
+    mac = mac_learning_lookup(ml, flow->dl_src, vlan);
+    if (!mac || mac_entry_age(ml, mac)) {
+        return true;
+    }
+
+    if (is_gratuitous_arp(flow, wc)) {
+        /* We don't want to learn from gratuitous ARP packets that are
+         * reflected back over bond slaves so we lock the learning table. */
+        if (!in_xbundle->bond) {
+            return true;
+        } else if (mac_entry_is_grat_arp_locked(mac)) {
+            return false;
+        }
+    }
+
+    return mac->port.p != in_xbundle->ofbundle;
+}
+
+
+/* Updates MAC learning table 'ml' given that a packet matching 'flow' was
+ * received on 'in_xbundle' in 'vlan'.
+ *
+ * This code repeats all the checks in is_mac_learning_update_needed() because
+ * the lock was released between there and here and thus the MAC learning state
+ * could have changed.
+ *
+ * Keep the code here synchronized with that in is_mac_learning_update_needed()
+ * above. */
+static void
+update_learning_table__(const struct xbridge *xbridge,
+                        const struct flow *flow, struct flow_wildcards *wc,
+                        int vlan, struct xbundle *in_xbundle)
+    OVS_REQ_WRLOCK(xbridge->ml->rwlock)
+{
+    struct mac_entry *mac;
+
     if (!mac_learning_may_learn(xbridge->ml, flow->dl_src, vlan)) {
-        goto out;
+        return;
     }
 
     mac = mac_learning_insert(xbridge->ml, flow->dl_src, vlan);
@@ -1049,7 +1107,7 @@ update_learning_table(const struct xbridge *xbridge,
         if (!in_xbundle->bond) {
             mac_entry_set_grat_arp_lock(mac);
         } else if (mac_entry_is_grat_arp_locked(mac)) {
-            goto out;
+            return;
         }
     }
 
@@ -1057,6 +1115,7 @@ update_learning_table(const struct xbridge *xbridge,
         /* The log messages here could actually be useful in debugging,
          * so keep the rate limit relatively high. */
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
+
         VLOG_DBG_RL(&rl, "bridge %s: learned that "ETH_ADDR_FMT" is "
                     "on port %s in VLAN %d",
                     xbridge->name, ETH_ADDR_ARGS(flow->dl_src),
@@ -1065,8 +1124,32 @@ update_learning_table(const struct xbridge *xbridge,
         mac->port.p = in_xbundle->ofbundle;
         mac_learning_changed(xbridge->ml);
     }
-out:
+}
+
+static void
+update_learning_table(const struct xbridge *xbridge,
+                      const struct flow *flow, struct flow_wildcards *wc,
+                      int vlan, struct xbundle *in_xbundle)
+{
+    bool need_update;
+
+    /* Don't learn the OFPP_NONE port. */
+    if (in_xbundle == &ofpp_none_bundle) {
+        return;
+    }
+
+    /* First try the common case: no change to MAC learning table. */
+    ovs_rwlock_rdlock(&xbridge->ml->rwlock);
+    need_update = is_mac_learning_update_needed(xbridge->ml, flow, wc, vlan,
+                                                in_xbundle);
     ovs_rwlock_unlock(&xbridge->ml->rwlock);
+
+    if (need_update) {
+        /* Slow path: MAC learning table might need an update. */
+        ovs_rwlock_wrlock(&xbridge->ml->rwlock);
+        update_learning_table__(xbridge, flow, wc, vlan, in_xbundle);
+        ovs_rwlock_unlock(&xbridge->ml->rwlock);
+    }
 }
 
 /* Determines whether packets in 'flow' within 'xbridge' should be forwarded or
@@ -1493,7 +1576,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         }
 
         ctx->xin->flow = old_flow;
-        ctx->xbridge = xport->xbundle->xbridge;
+        ctx->xbridge = xport->xbridge;
 
         if (ctx->xin->resubmit_stats) {
             netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats);
@@ -1586,14 +1669,18 @@ ctx_rule_hooks(struct xlate_ctx *ctx, struct rule_dpif *rule,
         ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
     }
     if (rule == NULL && may_packet_in) {
+        struct xport *xport;
+
         /* XXX
          * check if table configuration flags
          * OFPTC_TABLE_MISS_CONTROLLER, default.
          * OFPTC_TABLE_MISS_CONTINUE,
          * OFPTC_TABLE_MISS_DROP
-         * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do?
-         */
-        rule = rule_dpif_miss_rule(ctx->xbridge->ofproto, &ctx->xin->flow);
+         * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
+        xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
+        rule = choose_miss_rule(xport ? xport->config : 0,
+                                ctx->xbridge->miss_rule,
+                                ctx->xbridge->no_packet_in_rule);
     }
     if (rule && ctx->xin->resubmit_stats) {
         rule_credit_stats(rule, ctx->xin->resubmit_stats);
@@ -1688,7 +1775,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
                           enum ofp_packet_in_reason reason,
                           uint16_t controller_id)
 {
-    struct ofputil_packet_in pin;
+    struct ofputil_packet_in *pin;
     struct ofpbuf *packet;
     struct flow key;
 
@@ -1710,17 +1797,18 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
                         ctx->xout->odp_actions.size, NULL, NULL);
 
-    pin.packet = packet->data;
-    pin.packet_len = packet->size;
-    pin.reason = reason;
-    pin.controller_id = controller_id;
-    pin.table_id = ctx->table_id;
-    pin.cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
+    pin = xmalloc(sizeof *pin);
+    pin->packet_len = packet->size;
+    pin->packet = ofpbuf_steal_data(packet);
+    pin->reason = reason;
+    pin->controller_id = controller_id;
+    pin->table_id = ctx->table_id;
+    pin->cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
 
-    pin.send_len = len;
-    flow_get_metadata(&ctx->xin->flow, &pin.fmd);
+    pin->send_len = len;
+    flow_get_metadata(&ctx->xin->flow, &pin->fmd);
 
-    ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, &pin);
+    ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin);
     ofpbuf_delete(packet);
 }
 
@@ -2035,12 +2123,16 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
     if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
         struct rule_dpif *rule = ctx->rule;
 
-         if (list_is_empty(&rule->up.expirable)) {
-             list_insert(&rule->up.ofproto->expirable, &rule->up.expirable);
-         }
+        ovs_mutex_lock(&rule->up.ofproto->expirable_mutex);
+        if (list_is_empty(&rule->up.expirable)) {
+            list_insert(&rule->up.ofproto->expirable, &rule->up.expirable);
+        }
+        ovs_mutex_unlock(&rule->up.ofproto->expirable_mutex);
 
+        ovs_mutex_lock(&rule->up.timeout_mutex);
         reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout);
         reduce_timeout(oft->fin_hard_timeout, &rule->up.hard_timeout);
+        ovs_mutex_unlock(&rule->up.timeout_mutex);
     }
 }
 
@@ -2478,6 +2570,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 
     COVERAGE_INC(xlate_actions);
 
+    ovs_rwlock_rdlock(&xlate_rwlock);
+
     /* Flow initialization rules:
      * - 'base_flow' must match the kernel's view of the packet at the
      *   time that action processing starts.  'flow' represents any
@@ -2513,7 +2607,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 
     ctx.xbridge = xbridge_lookup(xin->ofproto);
     if (!ctx.xbridge) {
-        return;
+        goto out;
     }
 
     ctx.rule = xin->rule;
@@ -2570,7 +2664,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
             break;
 
         case OFPC_FRAG_DROP:
-            return;
+            goto out;
 
         case OFPC_FRAG_REASM:
             NOT_REACHED();
@@ -2631,4 +2725,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
      * use non-header fields as part of the cache. */
     memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
     memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
+
+out:
+    ovs_rwlock_unlock(&xlate_rwlock);
 }
index 9f8ff44..1c37bc3 100644 (file)
@@ -110,20 +110,24 @@ struct xlate_in {
     const struct dpif_flow_stats *resubmit_stats;
 };
 
+extern struct ovs_rwlock xlate_rwlock;
+
 void xlate_ofproto_set(struct ofproto_dpif *, const char *name,
-                       struct dpif *, const struct mac_learning *,
-                       struct stp *, const struct mbridge *,
-                       const struct dpif_sflow *, const struct dpif_ipfix *,
-                       enum ofp_config_flags, bool forward_bpdu,
-                       bool has_in_band, bool has_netflow);
-void xlate_remove_ofproto(struct ofproto_dpif *);
+                       struct dpif *, struct rule_dpif *miss_rule,
+                       struct rule_dpif *no_packet_in_rule,
+                       const struct mac_learning *, struct stp *,
+                       const struct mbridge *, const struct dpif_sflow *,
+                       const struct dpif_ipfix *, enum ofp_config_flags,
+                       bool forward_bpdu, bool has_in_band, bool has_netflow)
+    OVS_REQ_WRLOCK(xlate_rwlock);
+void xlate_remove_ofproto(struct ofproto_dpif *) OVS_REQ_WRLOCK(xlate_rwlock);
 
 void xlate_bundle_set(struct ofproto_dpif *, struct ofbundle *,
                       const char *name, enum port_vlan_mode, int vlan,
                       unsigned long *trunks, bool use_priority_tags,
                       const struct bond *, const struct lacp *,
-                      bool floodable);
-void xlate_bundle_remove(struct ofbundle *);
+                      bool floodable) OVS_REQ_WRLOCK(xlate_rwlock);
+void xlate_bundle_remove(struct ofbundle *) OVS_REQ_WRLOCK(xlate_rwlock);
 
 void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
                       struct ofport_dpif *, ofp_port_t, odp_port_t,
@@ -131,15 +135,17 @@ void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
                       const struct bfd *, struct ofport_dpif *peer,
                       int stp_port_no, const struct ofproto_port_queue *qdscp,
                       size_t n_qdscp, enum ofputil_port_config, bool is_tunnel,
-                      bool may_enable);
-void xlate_ofport_remove(struct ofport_dpif *);
+                      bool may_enable) OVS_REQ_WRLOCK(xlate_rwlock);
+void xlate_ofport_remove(struct ofport_dpif *) OVS_REQ_WRLOCK(xlate_rwlock);
 
 int xlate_receive(const struct dpif_backer *, struct ofpbuf *packet,
                   const struct nlattr *key, size_t key_len,
                   struct flow *, enum odp_key_fitness *,
-                  struct ofproto_dpif **, odp_port_t *odp_in_port);
+                  struct ofproto_dpif **, odp_port_t *odp_in_port)
+    OVS_EXCLUDED(xlate_rwlock);
 
-void xlate_actions(struct xlate_in *, struct xlate_out *);
+void xlate_actions(struct xlate_in *, struct xlate_out *)
+    OVS_EXCLUDED(xlate_rwlock);
 void xlate_in_init(struct xlate_in *, struct ofproto_dpif *,
                    const struct flow *, struct rule_dpif *,
                    uint8_t tcp_flags, const struct ofpbuf *packet);
index a8e5cd5..1582619 100644 (file)
@@ -71,6 +71,7 @@ COVERAGE_DEFINE(facet_revalidate);
 COVERAGE_DEFINE(facet_unexpected);
 COVERAGE_DEFINE(facet_suppress);
 COVERAGE_DEFINE(subfacet_install_fail);
+COVERAGE_DEFINE(packet_in_overflow);
 COVERAGE_DEFINE(flow_mod_overflow);
 
 /* Number of implemented OpenFlow tables. */
@@ -501,6 +502,10 @@ struct ofproto_dpif {
     struct ovs_mutex flow_mod_mutex;
     struct list flow_mods OVS_GUARDED;
     size_t n_flow_mods OVS_GUARDED;
+
+    struct ovs_mutex pin_mutex;
+    struct list pins OVS_GUARDED;
+    size_t n_pins OVS_GUARDED;
 };
 
 /* Defer flow mod completion until "ovs-appctl ofproto/unclog"?  (Useful only
@@ -570,7 +575,18 @@ void
 ofproto_dpif_send_packet_in(struct ofproto_dpif *ofproto,
                             struct ofputil_packet_in *pin)
 {
-    connmgr_send_packet_in(ofproto->up.connmgr, pin);
+    ovs_mutex_lock(&ofproto->pin_mutex);
+    if (ofproto->n_pins > 1024) {
+        ovs_mutex_unlock(&ofproto->pin_mutex);
+        COVERAGE_INC(packet_in_overflow);
+        free(CONST_CAST(void *, pin->packet));
+        free(pin);
+        return;
+    }
+
+    list_push_back(&ofproto->pins, &pin->list_node);
+    ofproto->n_pins++;
+    ovs_mutex_unlock(&ofproto->pin_mutex);
 }
 \f
 /* Factory functions. */
@@ -782,8 +798,10 @@ type_run(const char *type)
                 continue;
             }
 
+            ovs_rwlock_wrlock(&xlate_rwlock);
             xlate_ofproto_set(ofproto, ofproto->up.name,
-                              ofproto->backer->dpif, ofproto->ml,
+                              ofproto->backer->dpif, ofproto->miss_rule,
+                              ofproto->no_packet_in_rule, ofproto->ml,
                               ofproto->stp, ofproto->mbridge,
                               ofproto->sflow, ofproto->ipfix,
                               ofproto->up.frag_handling,
@@ -811,8 +829,13 @@ type_run(const char *type)
                                  ofport->up.pp.config, ofport->is_tunnel,
                                  ofport->may_enable);
             }
+            ovs_rwlock_unlock(&xlate_rwlock);
 
+            /* Only ofproto-dpif cares about the facet classifier so we just
+             * lock cls_cursor_init() to appease the thread safety analysis. */
+            ovs_rwlock_rdlock(&ofproto->facets.rwlock);
             cls_cursor_init(&cursor, &ofproto->facets, NULL);
+            ovs_rwlock_unlock(&ofproto->facets.rwlock);
             CLS_CURSOR_FOR_EACH_SAFE (facet, next, cr, &cursor) {
                 facet_revalidate(facet);
                 run_fast_rl();
@@ -1287,6 +1310,12 @@ construct(struct ofproto *ofproto_)
     ofproto->n_flow_mods = 0;
     ovs_mutex_unlock(&ofproto->flow_mod_mutex);
 
+    ovs_mutex_init(&ofproto->pin_mutex, PTHREAD_MUTEX_NORMAL);
+    ovs_mutex_lock(&ofproto->pin_mutex);
+    list_init(&ofproto->pins);
+    ofproto->n_pins = 0;
+    ovs_mutex_unlock(&ofproto->pin_mutex);
+
     ofproto_dpif_unixctl_init();
 
     hmap_init(&ofproto->vlandev_map);
@@ -1417,11 +1446,14 @@ destruct(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct rule_dpif *rule, *next_rule;
+    struct ofputil_flow_mod *pin, *next_pin;
     struct ofputil_flow_mod *fm, *next_fm;
     struct oftable *table;
 
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    ovs_rwlock_wrlock(&xlate_rwlock);
     xlate_remove_ofproto(ofproto);
+    ovs_rwlock_unlock(&xlate_rwlock);
 
     hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
     complete_operations(ofproto);
@@ -1429,10 +1461,12 @@ destruct(struct ofproto *ofproto_)
     OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
         struct cls_cursor cursor;
 
+        ovs_rwlock_wrlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
-            ofproto_rule_destroy(&rule->up);
+            ofproto_rule_destroy(&ofproto->up, &table->cls, &rule->up);
         }
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
 
     ovs_mutex_lock(&ofproto->flow_mod_mutex);
@@ -1445,6 +1479,16 @@ destruct(struct ofproto *ofproto_)
     ovs_mutex_unlock(&ofproto->flow_mod_mutex);
     ovs_mutex_destroy(&ofproto->flow_mod_mutex);
 
+    ovs_mutex_lock(&ofproto->pin_mutex);
+    LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &ofproto->pins) {
+        list_remove(&pin->list_node);
+        ofproto->n_pins--;
+        free(pin->ofpacts);
+        free(pin);
+    }
+    ovs_mutex_unlock(&ofproto->pin_mutex);
+    ovs_mutex_destroy(&ofproto->pin_mutex);
+
     mbridge_unref(ofproto->mbridge);
 
     netflow_destroy(ofproto->netflow);
@@ -1470,9 +1514,10 @@ static int
 run_fast(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
-    struct ofputil_flow_mod *fm, *next;
+    struct ofputil_packet_in *pin, *next_pin;
+    struct ofputil_flow_mod *fm, *next_fm;
+    struct list flow_mods, pins;
     struct ofport_dpif *ofport;
-    struct list flow_mods;
 
     /* Do not perform any periodic activity required by 'ofproto' while
      * waiting for flow restore to complete. */
@@ -1491,7 +1536,7 @@ run_fast(struct ofproto *ofproto_)
     }
     ovs_mutex_unlock(&ofproto->flow_mod_mutex);
 
-    LIST_FOR_EACH_SAFE (fm, next, list_node, &flow_mods) {
+    LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
         int error = ofproto_flow_mod(&ofproto->up, fm);
         if (error && !VLOG_DROP_WARN(&rl)) {
             VLOG_WARN("learning action failed to modify flow table (%s)",
@@ -1503,6 +1548,24 @@ run_fast(struct ofproto *ofproto_)
         free(fm);
     }
 
+    ovs_mutex_lock(&ofproto->pin_mutex);
+    if (ofproto->n_pins) {
+        pins = ofproto->pins;
+        list_moved(&pins);
+        list_init(&ofproto->pins);
+        ofproto->n_pins = 0;
+    } else {
+        list_init(&pins);
+    }
+    ovs_mutex_unlock(&ofproto->pin_mutex);
+
+    LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
+        connmgr_send_packet_in(ofproto->up.connmgr, pin);
+        list_remove(&pin->list_node);
+        free(CONST_CAST(void *, pin->packet));
+        free(pin);
+    }
+
     HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
         port_run_fast(ofport);
     }
@@ -1564,6 +1627,7 @@ run(struct ofproto *ofproto_)
     ovs_rwlock_unlock(&ofproto->ml->rwlock);
 
     /* Check the consistency of a random facet, to aid debugging. */
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     if (time_msec() >= ofproto->consistency_rl
         && !classifier_is_empty(&ofproto->facets)
         && !ofproto->backer->need_revalidate) {
@@ -1583,6 +1647,7 @@ run(struct ofproto *ofproto_)
             ofproto->backer->need_revalidate = REV_INCONSISTENCY;
         }
     }
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
 
     return 0;
 }
@@ -1635,12 +1700,16 @@ get_memory_usage(const struct ofproto *ofproto_, struct simap *usage)
     size_t n_subfacets = 0;
     struct facet *facet;
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     simap_increase(usage, "facets", classifier_count(&ofproto->facets));
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     cls_cursor_init(&cursor, &ofproto->facets, NULL);
     CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
         n_subfacets += list_size(&facet->subfacets);
     }
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
     simap_increase(usage, "subfacets", n_subfacets);
 }
 
@@ -1811,7 +1880,9 @@ port_destruct(struct ofport *port_)
     const char *dp_port_name;
 
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    ovs_rwlock_wrlock(&xlate_rwlock);
     xlate_ofport_remove(port);
+    ovs_rwlock_unlock(&xlate_rwlock);
 
     dp_port_name = netdev_vport_get_dpif_port(port->up.netdev, namebuf,
                                               sizeof namebuf);
@@ -2402,7 +2473,9 @@ bundle_destroy(struct ofbundle *bundle)
     ofproto = bundle->ofproto;
     mbridge_unregister_bundle(ofproto->mbridge, bundle->aux);
 
+    ovs_rwlock_wrlock(&xlate_rwlock);
     xlate_bundle_remove(bundle);
+    ovs_rwlock_unlock(&xlate_rwlock);
 
     LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
         bundle_del_port(port);
@@ -3976,10 +4049,12 @@ expire(struct dpif_backer *backer)
 
         /* Expire OpenFlow flows whose idle_timeout or hard_timeout
          * has passed. */
+        ovs_mutex_lock(&ofproto->up.expirable_mutex);
         LIST_FOR_EACH_SAFE (rule, next_rule, expirable,
                             &ofproto->up.expirable) {
             rule_expire(rule_dpif_cast(rule));
         }
+        ovs_mutex_unlock(&ofproto->up.expirable_mutex);
 
         /* All outstanding data in existing flows has been accounted, so it's a
          * good time to do bond rebalancing. */
@@ -4241,6 +4316,7 @@ expire_subfacets(struct dpif_backer *backer, int dp_max_idle)
 static void
 rule_expire(struct rule_dpif *rule)
 {
+    uint16_t idle_timeout, hard_timeout;
     long long int now;
     uint8_t reason;
 
@@ -4249,13 +4325,16 @@ rule_expire(struct rule_dpif *rule)
         return;
     }
 
+    ovs_mutex_lock(&rule->up.timeout_mutex);
+    hard_timeout = rule->up.hard_timeout;
+    idle_timeout = rule->up.idle_timeout;
+    ovs_mutex_unlock(&rule->up.timeout_mutex);
+
     /* Has 'rule' expired? */
     now = time_msec();
-    if (rule->up.hard_timeout
-        && now > rule->up.modified + rule->up.hard_timeout * 1000) {
+    if (hard_timeout && now > rule->up.modified + hard_timeout * 1000) {
         reason = OFPRR_HARD_TIMEOUT;
-    } else if (rule->up.idle_timeout
-               && now > rule->up.used + rule->up.idle_timeout * 1000) {
+    } else if (idle_timeout && now > rule->up.used + idle_timeout * 1000) {
         reason = OFPRR_IDLE_TIMEOUT;
     } else {
         return;
@@ -4305,7 +4384,9 @@ facet_create(const struct flow_miss *miss, struct rule_dpif *rule,
 
     match_init(&match, &facet->flow, &facet->xout.wc);
     cls_rule_init(&facet->cr, &match, OFP_DEFAULT_PRIORITY);
+    ovs_rwlock_wrlock(&ofproto->facets.rwlock);
     classifier_insert(&ofproto->facets, &facet->cr);
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
 
     facet->nf_flow.output_iface = facet->xout.nf_output_iface;
     facet->fail_open = rule->up.cr.priority == FAIL_OPEN_PRIORITY;
@@ -4373,7 +4454,9 @@ facet_remove(struct facet *facet)
                         &facet->subfacets) {
         subfacet_destroy__(subfacet);
     }
+    ovs_rwlock_wrlock(&facet->ofproto->facets.rwlock);
     classifier_remove(&facet->ofproto->facets, &facet->cr);
+    ovs_rwlock_unlock(&facet->ofproto->facets.rwlock);
     cls_rule_destroy(&facet->cr);
     facet_free(facet);
 }
@@ -4517,7 +4600,11 @@ facet_flush_stats(struct facet *facet)
 static struct facet *
 facet_find(struct ofproto_dpif *ofproto, const struct flow *flow)
 {
-    struct cls_rule *cr = classifier_lookup(&ofproto->facets, flow, NULL);
+    struct cls_rule *cr;
+
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
+    cr = classifier_lookup(&ofproto->facets, flow, NULL);
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
     return cr ? CONTAINER_OF(cr, struct facet, cr) : NULL;
 }
 
@@ -4762,6 +4849,7 @@ push_all_stats__(bool run_fast)
         struct cls_cursor cursor;
         struct facet *facet;
 
+        ovs_rwlock_rdlock(&ofproto->facets.rwlock);
         cls_cursor_init(&cursor, &ofproto->facets, NULL);
         CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
             facet_push_stats(facet, false);
@@ -4769,6 +4857,7 @@ push_all_stats__(bool run_fast)
                 run_fast_rl();
             }
         }
+        ovs_rwlock_unlock(&ofproto->facets.rwlock);
     }
 
     rl = time_msec() + 100;
@@ -5047,14 +5136,21 @@ static struct rule_dpif *
 rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
                  struct flow_wildcards *wc)
 {
+    struct ofport_dpif *port;
     struct rule_dpif *rule;
 
     rule = rule_dpif_lookup_in_table(ofproto, flow, wc, 0);
     if (rule) {
         return rule;
     }
+    port = get_ofp_port(ofproto, flow->in_port.ofp_port);
+    if (!port) {
+        VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
+                     flow->in_port.ofp_port);
+    }
 
-    return rule_dpif_miss_rule(ofproto, flow);
+    return choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+                            ofproto->no_packet_in_rule);
 }
 
 struct rule_dpif *
@@ -5082,34 +5178,30 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
         struct flow ofpc_normal_flow = *flow;
         ofpc_normal_flow.tp_src = htons(0);
         ofpc_normal_flow.tp_dst = htons(0);
+        ovs_rwlock_rdlock(&cls->rwlock);
         cls_rule = classifier_lookup(cls, &ofpc_normal_flow, wc);
+        ovs_rwlock_unlock(&cls->rwlock);
     } else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
         cls_rule = &ofproto->drop_frags_rule->up.cr;
         if (wc) {
             flow_wildcards_init_exact(wc);
         }
     } else {
+        ovs_rwlock_rdlock(&cls->rwlock);
         cls_rule = classifier_lookup(cls, flow, wc);
+        ovs_rwlock_unlock(&cls->rwlock);
     }
     return rule_dpif_cast(rule_from_cls_rule(cls_rule));
 }
 
+/* Given a port configuration (specified as zero if there's no port), chooses
+ * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
+ * flow table miss. */
 struct rule_dpif *
-rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow)
+choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
+                 struct rule_dpif *no_packet_in_rule)
 {
-    struct ofport_dpif *port;
-
-    port = get_ofp_port(ofproto, flow->in_port.ofp_port);
-    if (!port) {
-        VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
-                     flow->in_port.ofp_port);
-        return ofproto->miss_rule;
-    }
-
-    if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) {
-        return ofproto->no_packet_in_rule;
-    }
-    return ofproto->miss_rule;
+    return config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
 }
 
 static void
@@ -5425,10 +5517,12 @@ send_netflow_active_timeouts(struct ofproto_dpif *ofproto)
     struct cls_cursor cursor;
     struct facet *facet;
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     cls_cursor_init(&cursor, &ofproto->facets, NULL);
     CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
         send_active_timeout(ofproto, facet);
     }
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
 }
 \f
 static struct ofproto_dpif *
@@ -5827,12 +5921,14 @@ ofproto_dpif_self_check__(struct ofproto_dpif *ofproto, struct ds *reply)
     int errors;
 
     errors = 0;
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     cls_cursor_init(&cursor, &ofproto->facets, NULL);
     CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
         if (!facet_check_consistency(facet)) {
             errors++;
         }
     }
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
     if (errors) {
         ofproto->backer->need_revalidate = REV_INCONSISTENCY;
     }
@@ -6053,6 +6149,7 @@ ofproto_unixctl_dpif_dump_megaflows(struct unixctl_conn *conn,
         return;
     }
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
     cls_cursor_init(&cursor, &ofproto->facets, NULL);
     CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
         cls_rule_format(&facet->cr, &ds);
@@ -6075,6 +6172,7 @@ ofproto_unixctl_dpif_dump_megaflows(struct unixctl_conn *conn,
         }
         ds_put_cstr(&ds, "\n");
     }
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
 
     ds_chomp(&ds, '\n');
     unixctl_command_reply(conn, ds_cstr(&ds));
@@ -6377,7 +6475,7 @@ vlandev_find(const struct ofproto_dpif *ofproto, ofp_port_t vlandev_ofp_port)
 static ofp_port_t
 vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto,
                        ofp_port_t vlandev_ofp_port, int *vid)
-    OVS_REQ_WRLOCK(ofproto->vsp_mutex)
+    OVS_REQUIRES(ofproto->vsp_mutex)
 {
     if (!hmap_is_empty(&ofproto->vlandev_map)) {
         const struct vlan_splinter *vsp;
index 88593ce..a74146b 100644 (file)
@@ -22,6 +22,7 @@
 #include "ovs-thread.h"
 #include "timer.h"
 #include "util.h"
+#include "ovs-thread.h"
 
 union user_action_cookie;
 struct ofproto_dpif;
@@ -59,11 +60,12 @@ struct rule_dpif *rule_dpif_lookup_in_table(struct ofproto_dpif *,
                                             struct flow_wildcards *,
                                             uint8_t table_id);
 
-struct rule_dpif *rule_dpif_miss_rule(struct ofproto_dpif *ofproto,
-                                      const struct flow *);
-
 void rule_credit_stats(struct rule_dpif *, const struct dpif_flow_stats *);
 
+struct rule_dpif *choose_miss_rule(enum ofputil_port_config,
+                                   struct rule_dpif *miss_rule,
+                                   struct rule_dpif *no_packet_in_rule);
+
 bool ofproto_has_vlan_splinters(const struct ofproto_dpif *);
 ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
                                   ofp_port_t realdev_ofp_port,
index 41d106a..f081482 100644 (file)
@@ -19,7 +19,6 @@
 
 /* Definitions for use within ofproto. */
 
-#include "ofproto/ofproto.h"
 #include "cfm.h"
 #include "classifier.h"
 #include "heap.h"
@@ -27,6 +26,8 @@
 #include "list.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
+#include "ofproto/ofproto.h"
+#include "ovs-thread.h"
 #include "shash.h"
 #include "simap.h"
 #include "timeval.h"
@@ -75,7 +76,9 @@ struct ofproto {
 
     /* Optimisation for flow expiry.
      * These flows should all be present in tables. */
-    struct list expirable;      /* Expirable 'struct rule"s in all tables. */
+    struct ovs_mutex expirable_mutex;
+    struct list expirable OVS_GUARDED; /* Expirable 'struct rule"s in all
+                                          tables. */
 
     /* Meter table.
      * OpenFlow meters start at 1.  To avoid confusion we leave the first
@@ -219,11 +222,13 @@ struct rule {
     long long int created;       /* Creation time. */
     long long int modified;      /* Time of last modification. */
     long long int used;          /* Last use; time created if never used. */
-    uint16_t hard_timeout;       /* In seconds from ->modified. */
-    uint16_t idle_timeout;       /* In seconds from ->used. */
     uint8_t table_id;            /* Index in ofproto's 'tables' array. */
     bool send_flow_removed;      /* Send a flow removed message? */
 
+    struct ovs_mutex timeout_mutex;
+    uint16_t hard_timeout OVS_GUARDED; /* In seconds from ->modified. */
+    uint16_t idle_timeout OVS_GUARDED; /* In seconds from ->used. */
+
     /* Eviction groups. */
     bool evictable;              /* If false, prevents eviction. */
     struct heap_node evg_node;   /* In eviction_group's "rules" heap. */
@@ -261,7 +266,8 @@ rule_from_cls_rule(const struct cls_rule *cls_rule)
 
 void ofproto_rule_update_used(struct rule *, long long int used);
 void ofproto_rule_expire(struct rule *, uint8_t reason);
-void ofproto_rule_destroy(struct rule *);
+void ofproto_rule_destroy(struct ofproto *, struct classifier *cls,
+                          struct rule *) OVS_REQ_WRLOCK(cls->rwlock);
 
 bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t out_port);
 
index 0625ccf..3cdc72c 100644 (file)
@@ -153,6 +153,9 @@ static void oftable_enable_eviction(struct oftable *,
                                     size_t n_fields);
 
 static void oftable_remove_rule(struct rule *);
+static void oftable_remove_rule__(struct ofproto *ofproto,
+                                  struct classifier *cls, struct rule *rule)
+    OVS_REQ_WRLOCK(cls->rwlock);
 static struct rule *oftable_replace_rule(struct rule *);
 static void oftable_substitute_rule(struct rule *old, struct rule *new);
 
@@ -430,6 +433,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ofproto->n_tables = 0;
     hindex_init(&ofproto->cookies);
     list_init(&ofproto->expirable);
+    ovs_mutex_init(&ofproto->expirable_mutex, PTHREAD_MUTEX_RECURSIVE);
     ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
     ofproto->state = S_OPENFLOW;
     list_init(&ofproto->pending);
@@ -1017,6 +1021,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
     }
 
     table->max_flows = s->max_flows;
+    ovs_rwlock_rdlock(&table->cls.rwlock);
     if (classifier_count(&table->cls) > table->max_flows
         && table->eviction_fields) {
         /* 'table' contains more flows than allowed.  We might not be able to
@@ -1032,6 +1037,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
             break;
         }
     }
+    ovs_rwlock_unlock(&table->cls.rwlock);
 }
 \f
 bool
@@ -1065,15 +1071,17 @@ ofproto_flush__(struct ofproto *ofproto)
             continue;
         }
 
+        ovs_rwlock_wrlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
             if (!rule->pending) {
                 ofoperation_create(group, rule, OFOPERATION_DELETE,
                                    OFPRR_DELETE);
-                oftable_remove_rule(rule);
+                oftable_remove_rule__(ofproto, &table->cls, rule);
                 ofproto->ofproto_class->rule_destruct(rule);
             }
         }
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
     ofopgroup_submit(group);
 }
@@ -1115,6 +1123,7 @@ ofproto_destroy__(struct ofproto *ofproto)
 
     free(ofproto->vlan_bitmap);
 
+    ovs_mutex_destroy(&ofproto->expirable_mutex);
     ofproto->ofproto_class->dealloc(ofproto);
 }
 
@@ -1385,7 +1394,9 @@ ofproto_get_memory_usage(const struct ofproto *ofproto, struct simap *usage)
 
     n_rules = 0;
     OFPROTO_FOR_EACH_TABLE (table, ofproto) {
+        ovs_rwlock_rdlock(&table->cls.rwlock);
         n_rules += classifier_count(&table->cls);
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
     simap_increase(usage, "rules", n_rules);
 
@@ -1612,8 +1623,10 @@ ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
 {
     const struct rule *rule;
 
+    ovs_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
     rule = rule_from_cls_rule(classifier_find_match_exactly(
                                   &ofproto->tables[0].cls, match, priority));
+    ovs_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
     if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
                                 ofpacts, ofpacts_len)) {
         struct ofputil_flow_mod fm;
@@ -1650,8 +1663,10 @@ ofproto_delete_flow(struct ofproto *ofproto,
 {
     struct rule *rule;
 
+    ovs_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
     rule = rule_from_cls_rule(classifier_find_match_exactly(
                                   &ofproto->tables[0].cls, target, priority));
+    ovs_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
     if (!rule) {
         /* No such rule -> success. */
         return true;
@@ -2165,6 +2180,7 @@ ofproto_rule_destroy__(struct rule *rule)
     if (rule) {
         cls_rule_destroy(&rule->cr);
         free(rule->ofpacts);
+        ovs_mutex_destroy(&rule->timeout_mutex);
         rule->ofproto->ofproto_class->rule_dealloc(rule);
     }
 }
@@ -2178,10 +2194,11 @@ ofproto_rule_destroy__(struct rule *rule)
  * This function should only be called from an ofproto implementation's
  * ->destruct() function.  It is not suitable elsewhere. */
 void
-ofproto_rule_destroy(struct rule *rule)
+ofproto_rule_destroy(struct ofproto *ofproto, struct classifier *cls,
+                     struct rule *rule) OVS_REQ_WRLOCK(cls->rwlock)
 {
     ovs_assert(!rule->pending);
-    oftable_remove_rule(rule);
+    oftable_remove_rule__(ofproto, cls, rule);
     ofproto_rule_destroy__(rule);
 }
 
@@ -2613,7 +2630,9 @@ handle_table_stats_request(struct ofconn *ofconn,
         ots[i].instructions = htonl(OFPIT11_ALL);
         ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
         ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
+        ovs_rwlock_rdlock(&p->tables[i].cls.rwlock);
         ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
+        ovs_rwlock_unlock(&p->tables[i].cls.rwlock);
     }
 
     p->ofproto_class->get_tables(p, ots);
@@ -2880,9 +2899,11 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
         struct cls_cursor cursor;
         struct rule *rule;
 
+        ovs_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, &cr);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             if (rule->pending) {
+                ovs_rwlock_unlock(&table->cls.rwlock);
                 error = OFPROTO_POSTPONE;
                 goto exit;
             }
@@ -2892,6 +2913,7 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
                 list_push_back(rules, &rule->ofproto_node);
             }
         }
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
 
 exit:
@@ -2956,8 +2978,10 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
     FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
         struct rule *rule;
 
+        ovs_rwlock_rdlock(&table->cls.rwlock);
         rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
                                                                &cr));
+        ovs_rwlock_unlock(&table->cls.rwlock);
         if (rule) {
             if (rule->pending) {
                 error = OFPROTO_POSTPONE;
@@ -3019,8 +3043,6 @@ handle_flow_stats_request(struct ofconn *ofconn,
         fs.cookie = rule->flow_cookie;
         fs.table_id = rule->table_id;
         calc_duration(rule->created, now, &fs.duration_sec, &fs.duration_nsec);
-        fs.idle_timeout = rule->idle_timeout;
-        fs.hard_timeout = rule->hard_timeout;
         fs.idle_age = age_secs(now - rule->used);
         fs.hard_age = age_secs(now - rule->modified);
         ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
@@ -3028,6 +3050,12 @@ handle_flow_stats_request(struct ofconn *ofconn,
         fs.ofpacts = rule->ofpacts;
         fs.ofpacts_len = rule->ofpacts_len;
         fs.flags = 0;
+
+        ovs_mutex_lock(&rule->timeout_mutex);
+        fs.idle_timeout = rule->idle_timeout;
+        fs.hard_timeout = rule->hard_timeout;
+        ovs_mutex_unlock(&rule->timeout_mutex);
+
         if (rule->send_flow_removed) {
             fs.flags |= OFPFF_SEND_FLOW_REM;
             /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
@@ -3073,10 +3101,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
         struct cls_cursor cursor;
         struct rule *rule;
 
+        ovs_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             flow_stats_ds(rule, results);
         }
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
 }
 
@@ -3306,6 +3336,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     struct rule *victim;
     struct rule *rule;
     uint8_t table_id;
+    bool overlaps;
     int error;
 
     error = check_table_id(ofproto, fm->table_id);
@@ -3362,8 +3393,10 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     }
 
     /* Check for overlap, if requested. */
-    if (fm->flags & OFPFF_CHECK_OVERLAP
-        && classifier_rule_overlaps(&table->cls, &rule->cr)) {
+    ovs_rwlock_rdlock(&table->cls.rwlock);
+    overlaps = classifier_rule_overlaps(&table->cls, &rule->cr);
+    ovs_rwlock_unlock(&table->cls.rwlock);
+    if (fm->flags & OFPFF_CHECK_OVERLAP && overlaps) {
         cls_rule_destroy(&rule->cr);
         ofproto->ofproto_class->rule_dealloc(rule);
         return OFPERR_OFPFMFC_OVERLAP;
@@ -3375,8 +3408,13 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     rule->pending = NULL;
     rule->flow_cookie = fm->new_cookie;
     rule->created = rule->modified = rule->used = time_msec();
+
+    ovs_mutex_init(&rule->timeout_mutex, OVS_MUTEX_ADAPTIVE);
+    ovs_mutex_lock(&rule->timeout_mutex);
     rule->idle_timeout = fm->idle_timeout;
     rule->hard_timeout = fm->hard_timeout;
+    ovs_mutex_unlock(&rule->timeout_mutex);
+
     rule->table_id = table - ofproto->tables;
     rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
     /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
@@ -3401,8 +3439,12 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     } else {
         struct ofoperation *op;
         struct rule *evict;
+        size_t n_rules;
 
-        if (classifier_count(&table->cls) > table->max_flows) {
+        ovs_rwlock_rdlock(&table->cls.rwlock);
+        n_rules = classifier_count(&table->cls);
+        ovs_rwlock_unlock(&table->cls.rwlock);
+        if (n_rules > table->max_flows) {
             bool was_evictable;
 
             was_evictable = rule->evictable;
@@ -3660,8 +3702,10 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
     fr.table_id = rule->table_id;
     calc_duration(rule->created, time_msec(),
                   &fr.duration_sec, &fr.duration_nsec);
+    ovs_mutex_lock(&rule->timeout_mutex);
     fr.idle_timeout = rule->idle_timeout;
     fr.hard_timeout = rule->hard_timeout;
+    ovs_mutex_unlock(&rule->timeout_mutex);
     rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
                                                  &fr.byte_count);
 
@@ -3967,8 +4011,10 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     fu.event = (flags & (NXFMF_INITIAL | NXFMF_ADD)
                 ? NXFME_ADDED : NXFME_MODIFIED);
     fu.reason = 0;
+    ovs_mutex_lock(&rule->timeout_mutex);
     fu.idle_timeout = rule->idle_timeout;
     fu.hard_timeout = rule->hard_timeout;
+    ovs_mutex_unlock(&rule->timeout_mutex);
     fu.table_id = rule->table_id;
     fu.cookie = rule->flow_cookie;
     minimatch_expand(&rule->cr.match, &match);
@@ -4083,11 +4129,13 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
         struct cls_cursor cursor;
         struct rule *rule;
 
+        ovs_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, &target);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             ovs_assert(!rule->pending); /* XXX */
             ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
         }
+        ovs_rwlock_unlock(&table->cls.rwlock);
     }
 
     HMAP_FOR_EACH (op, hmap_node, &ofproto->deletions) {
@@ -5069,9 +5117,17 @@ ofproto_evict(struct ofproto *ofproto)
 
     group = ofopgroup_create_unattached(ofproto);
     OFPROTO_FOR_EACH_TABLE (table, ofproto) {
-        while (classifier_count(&table->cls) > table->max_flows
-               && table->eviction_fields) {
+        while (table->eviction_fields) {
             struct rule *rule;
+            size_t n_rules;
+
+            ovs_rwlock_rdlock(&table->cls.rwlock);
+            n_rules = classifier_count(&table->cls);
+            ovs_rwlock_unlock(&table->cls.rwlock);
+
+            if (n_rules <= table->max_flows) {
+                break;
+            }
 
             rule = choose_rule_to_evict(table);
             if (!rule || rule->pending) {
@@ -5218,6 +5274,7 @@ rule_eviction_priority(struct rule *rule)
     uint32_t expiration_offset;
 
     /* Calculate time of expiration. */
+    ovs_mutex_lock(&rule->timeout_mutex);
     hard_expiration = (rule->hard_timeout
                        ? rule->modified + rule->hard_timeout * 1000
                        : LLONG_MAX);
@@ -5225,6 +5282,7 @@ rule_eviction_priority(struct rule *rule)
                        ? rule->used + rule->idle_timeout * 1000
                        : LLONG_MAX);
     expiration = MIN(hard_expiration, idle_expiration);
+    ovs_mutex_unlock(&rule->timeout_mutex);
     if (expiration == LLONG_MAX) {
         return 0;
     }
@@ -5251,9 +5309,13 @@ eviction_group_add_rule(struct rule *rule)
 {
     struct ofproto *ofproto = rule->ofproto;
     struct oftable *table = &ofproto->tables[rule->table_id];
+    bool has_timeout;
 
-    if (table->eviction_fields
-        && (rule->hard_timeout || rule->idle_timeout)) {
+    ovs_mutex_lock(&rule->timeout_mutex);
+    has_timeout = rule->hard_timeout || rule->idle_timeout;
+    ovs_mutex_unlock(&rule->timeout_mutex);
+
+    if (table->eviction_fields && has_timeout) {
         struct eviction_group *evg;
 
         evg = eviction_group_find(table, eviction_group_hash_rule(rule));
@@ -5282,7 +5344,9 @@ oftable_init(struct oftable *table)
 static void
 oftable_destroy(struct oftable *table)
 {
+    ovs_rwlock_rdlock(&table->cls.rwlock);
     ovs_assert(classifier_is_empty(&table->cls));
+    ovs_rwlock_unlock(&table->cls.rwlock);
     oftable_disable_eviction(table);
     classifier_destroy(&table->cls);
     free(table->name);
@@ -5362,33 +5426,46 @@ oftable_enable_eviction(struct oftable *table,
     hmap_init(&table->eviction_groups_by_id);
     heap_init(&table->eviction_groups_by_size);
 
+    ovs_rwlock_rdlock(&table->cls.rwlock);
     cls_cursor_init(&cursor, &table->cls, NULL);
     CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
         eviction_group_add_rule(rule);
     }
+    ovs_rwlock_unlock(&table->cls.rwlock);
 }
 
 /* Removes 'rule' from the oftable that contains it. */
 static void
-oftable_remove_rule(struct rule *rule)
+oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls,
+                      struct rule *rule) OVS_REQ_WRLOCK(cls->rwlock)
 {
-    struct ofproto *ofproto = rule->ofproto;
-    struct oftable *table = &ofproto->tables[rule->table_id];
-
-    classifier_remove(&table->cls, &rule->cr);
+    classifier_remove(cls, &rule->cr);
     if (rule->meter_id) {
         list_remove(&rule->meter_list_node);
     }
     cookies_remove(ofproto, rule);
     eviction_group_remove_rule(rule);
+    ovs_mutex_lock(&ofproto->expirable_mutex);
     if (!list_is_empty(&rule->expirable)) {
         list_remove(&rule->expirable);
     }
+    ovs_mutex_unlock(&ofproto->expirable_mutex);
     if (!list_is_empty(&rule->meter_list_node)) {
         list_remove(&rule->meter_list_node);
     }
 }
 
+static void
+oftable_remove_rule(struct rule *rule)
+{
+    struct ofproto *ofproto = rule->ofproto;
+    struct oftable *table = &ofproto->tables[rule->table_id];
+
+    ovs_rwlock_wrlock(&table->cls.rwlock);
+    oftable_remove_rule__(ofproto, &table->cls, rule);
+    ovs_rwlock_unlock(&table->cls.rwlock);
+}
+
 /* Inserts 'rule' into its oftable.  Removes any existing rule from 'rule''s
  * oftable that has an identical cls_rule.  Returns the rule that was removed,
  * if any, and otherwise NULL. */
@@ -5398,26 +5475,36 @@ oftable_replace_rule(struct rule *rule)
     struct ofproto *ofproto = rule->ofproto;
     struct oftable *table = &ofproto->tables[rule->table_id];
     struct rule *victim;
-    bool may_expire = rule->hard_timeout || rule->idle_timeout;
+    bool may_expire;
+
+    ovs_mutex_lock(&rule->timeout_mutex);
+    may_expire = rule->hard_timeout || rule->idle_timeout;
+    ovs_mutex_unlock(&rule->timeout_mutex);
 
     if (may_expire) {
+        ovs_mutex_lock(&ofproto->expirable_mutex);
         list_insert(&ofproto->expirable, &rule->expirable);
+        ovs_mutex_unlock(&ofproto->expirable_mutex);
     }
     cookies_insert(ofproto, rule);
     if (rule->meter_id) {
         struct meter *meter = ofproto->meters[rule->meter_id];
         list_insert(&meter->rules, &rule->meter_list_node);
     }
+    ovs_rwlock_wrlock(&table->cls.rwlock);
     victim = rule_from_cls_rule(classifier_replace(&table->cls, &rule->cr));
+    ovs_rwlock_unlock(&table->cls.rwlock);
     if (victim) {
         if (victim->meter_id) {
             list_remove(&victim->meter_list_node);
         }
         cookies_remove(ofproto, victim);
 
+        ovs_mutex_lock(&ofproto->expirable_mutex);
         if (!list_is_empty(&victim->expirable)) {
             list_remove(&victim->expirable);
         }
+        ovs_mutex_unlock(&ofproto->expirable_mutex);
         eviction_group_remove_rule(victim);
     }
     eviction_group_add_rule(rule);
index ce325c0..c23e2d7 100644 (file)
@@ -64,25 +64,25 @@ static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 static struct vlog_rate_limit dbg_rl = VLOG_RATE_LIMIT_INIT(60, 60);
 
-static struct tnl_port *tnl_find(struct tnl_match *) OVS_REQ_RDLOCK(&rwlock);
+static struct tnl_port *tnl_find(struct tnl_match *) OVS_REQ_RDLOCK(rwlock);
 static struct tnl_port *tnl_find_exact(struct tnl_match *)
-    OVS_REQ_RDLOCK(&rwlock);
+    OVS_REQ_RDLOCK(rwlock);
 static struct tnl_port *tnl_find_ofport(const struct ofport_dpif *)
-    OVS_REQ_RDLOCK(&rwlock);
+    OVS_REQ_RDLOCK(rwlock);
 
 static uint32_t tnl_hash(struct tnl_match *);
 static void tnl_match_fmt(const struct tnl_match *, struct ds *);
-static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(&rwlock);
+static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(rwlock);
 static void tnl_port_mod_log(const struct tnl_port *, const char *action)
-    OVS_REQ_RDLOCK(&rwlock);
+    OVS_REQ_RDLOCK(rwlock);
 static const char *tnl_port_get_name(const struct tnl_port *)
-    OVS_REQ_RDLOCK(&rwlock);
-static void tnl_port_del__(const struct ofport_dpif *) OVS_REQ_WRLOCK(&rwlock);
+    OVS_REQ_RDLOCK(rwlock);
+static void tnl_port_del__(const struct ofport_dpif *) OVS_REQ_WRLOCK(rwlock);
 
 static bool
 tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
                odp_port_t odp_port, bool warn)
-    OVS_REQ_WRLOCK(&rwlock)
+    OVS_REQ_WRLOCK(rwlock)
 {
     const struct netdev_tunnel_config *cfg;
     struct tnl_port *existing_port;
index 7fb1447..1d3d2d4 100644 (file)
@@ -396,6 +396,7 @@ get_value(unsigned int *x, unsigned n_values)
 
 static void
 compare_classifiers(struct classifier *cls, struct tcls *tcls)
+    OVS_REQ_RDLOCK(cls->rwlock)
 {
     static const int confidence = 500;
     unsigned int i;
@@ -444,17 +445,19 @@ destroy_classifier(struct classifier *cls)
     struct test_rule *rule, *next_rule;
     struct cls_cursor cursor;
 
+    ovs_rwlock_wrlock(&cls->rwlock);
     cls_cursor_init(&cursor, cls, NULL);
     CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cls_rule, &cursor) {
         classifier_remove(cls, &rule->cls_rule);
         free_rule(rule);
     }
+    ovs_rwlock_unlock(&cls->rwlock);
     classifier_destroy(cls);
 }
 
 static void
-check_tables(const struct classifier *cls,
-             int n_tables, int n_rules, int n_dups)
+check_tables(const struct classifier *cls, int n_tables, int n_rules,
+             int n_dups) OVS_REQ_RDLOCK(cls->rwlock)
 {
     const struct cls_table *table;
     struct test_rule *test_rule;
@@ -610,10 +613,12 @@ test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     struct tcls tcls;
 
     classifier_init(&cls);
+    ovs_rwlock_rdlock(&cls.rwlock);
     tcls_init(&tcls);
     assert(classifier_is_empty(&cls));
     assert(tcls_is_empty(&tcls));
     compare_classifiers(&cls, &tcls);
+    ovs_rwlock_unlock(&cls.rwlock);
     classifier_destroy(&cls);
     tcls_destroy(&tcls);
 }
@@ -640,6 +645,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
                          hash_bytes(&wc_fields, sizeof wc_fields, 0), 0);
 
         classifier_init(&cls);
+        ovs_rwlock_wrlock(&cls.rwlock);
         tcls_init(&tcls);
 
         tcls_rule = tcls_insert(&tcls, rule);
@@ -654,6 +660,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         compare_classifiers(&cls, &tcls);
 
         free_rule(rule);
+        ovs_rwlock_unlock(&cls.rwlock);
         classifier_destroy(&cls);
         tcls_destroy(&tcls);
     }
@@ -677,6 +684,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         rule2->aux += 5;
 
         classifier_init(&cls);
+        ovs_rwlock_wrlock(&cls.rwlock);
         tcls_init(&tcls);
         tcls_insert(&tcls, rule1);
         classifier_insert(&cls, &rule1->cls_rule);
@@ -692,6 +700,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         check_tables(&cls, 1, 1, 0);
         compare_classifiers(&cls, &tcls);
         tcls_destroy(&tcls);
+        ovs_rwlock_unlock(&cls.rwlock);
         destroy_classifier(&cls);
     }
 }
@@ -787,6 +796,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             }
 
             classifier_init(&cls);
+            ovs_rwlock_wrlock(&cls.rwlock);
             tcls_init(&tcls);
 
             for (i = 0; i < ARRAY_SIZE(ops); i++) {
@@ -825,6 +835,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
                 compare_classifiers(&cls, &tcls);
             }
 
+            ovs_rwlock_unlock(&cls.rwlock);
             classifier_destroy(&cls);
             tcls_destroy(&tcls);
 
@@ -887,6 +898,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         } while ((1 << count_ones(value_mask)) < N_RULES);
 
         classifier_init(&cls);
+        ovs_rwlock_wrlock(&cls.rwlock);
         tcls_init(&tcls);
 
         for (i = 0; i < N_RULES; i++) {
@@ -913,6 +925,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             compare_classifiers(&cls, &tcls);
         }
 
+        ovs_rwlock_unlock(&cls.rwlock);
         classifier_destroy(&cls);
         tcls_destroy(&tcls);
     }
@@ -947,6 +960,7 @@ test_many_rules_in_n_tables(int n_tables)
         shuffle(priorities, ARRAY_SIZE(priorities));
 
         classifier_init(&cls);
+        ovs_rwlock_wrlock(&cls.rwlock);
         tcls_init(&tcls);
 
         for (i = 0; i < MAX_RULES; i++) {
@@ -979,6 +993,7 @@ test_many_rules_in_n_tables(int n_tables)
             free_rule(target);
         }
 
+        ovs_rwlock_unlock(&cls.rwlock);
         destroy_classifier(&cls);
         tcls_destroy(&tcls);
     }
index 7e76d0e..61c21db 100755 (executable)
@@ -113,6 +113,7 @@ OPENVSWITCH_DEFAULT_SWITCH = '/etc/default/openvswitch-switch' # Debian
 OPENVSWITCH_SYSCONFIG_SWITCH = '/etc/sysconfig/openvswitch'    # RHEL
 OPENVSWITCH_DEFAULT_CONTROLLER = '/etc/default/openvswitch-controller'
 OPENVSWITCH_CONF_DB = '@DBDIR@/conf.db'
+OPENVSWITCH_COMPACT_DB = '@DBDIR@/bugtool-compact-conf.db'
 OPENVSWITCH_VSWITCHD_PID = '@RUNDIR@/ovs-vswitchd.pid'
 VAR_LOG_DIR = '/var/log/'
 VAR_LOG_CORE_DIR = '/var/log/core'
@@ -241,7 +242,7 @@ cap(CAP_LOSETUP_A,           PII_MAYBE,                 max_size=KB, max_time=5)
 cap(CAP_MULTIPATH,           PII_MAYBE,                 max_size=20*KB,
     max_time=10)
 cap(CAP_NETWORK_CONFIG,      PII_IF_CUSTOMIZED,
-                                        min_size=0,     max_size=40*KB)
+                                        min_size=0,     max_size=5*MB)
 cap(CAP_NETWORK_INFO,        PII_YES,                   max_size=50*MB,
     max_time=30)
 cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=-1,
@@ -543,7 +544,8 @@ exclude those logs from the archive.
     tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
     file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF, HOSTS])
     file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
-    file_output(CAP_NETWORK_CONFIG, [OPENVSWITCH_CONF_DB])
+    file_output(CAP_NETWORK_CONFIG, [OPENVSWITCH_DEFAULT_SWITCH,
+                OPENVSWITCH_SYSCONFIG_SWITCH, OPENVSWITCH_DEFAULT_CONTROLLER])
 
     cmd_output(CAP_NETWORK_INFO, [IFCONFIG, '-a'])
     cmd_output(CAP_NETWORK_INFO, [ROUTE, '-n'])
@@ -575,6 +577,8 @@ exclude those logs from the archive.
     tree_output(CAP_NETWORK_INFO, PROC_NET_VLAN_DIR)
     cmd_output(CAP_NETWORK_INFO, [TC, '-s', 'qdisc'])
     file_output(CAP_NETWORK_INFO, [PROC_NET_SOFTNET_STAT])
+
+    collect_ovsdb()
     if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
         cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show', '-s'])
         for d in dp_list():
@@ -679,6 +683,8 @@ exclude those logs from the archive.
         for c in caps.keys():
             print >>sys.stderr, "    %s (%d, %d)" % (c, caps[c][MAX_SIZE],
                                                      cap_sizes[c])
+
+    cleanup_ovsdb()
     return 0
 
 def dump_scsi_hosts(cap):
@@ -739,6 +745,36 @@ def dp_list():
         return output.getvalue().splitlines()
     return []
 
+def collect_ovsdb():
+    if not os.path.isfile(OPENVSWITCH_CONF_DB):
+        return
+
+    max_size = 10*MB
+
+    try:
+        if os.path.getsize(OPENVSWITCH_CONF_DB) > max_size:
+            if os.path.isfile(OPENVSWITCH_COMPACT_DB):
+                os.unlink(OPENVSWITCH_COMPACT_DB)
+
+            output = StringIO.StringIO()
+            max_time = 5
+            procs = [ProcOutput(['ovsdb-tool', 'compact',
+                                OPENVSWITCH_CONF_DB, OPENVSWITCH_COMPACT_DB],
+                                max_time, output)]
+            run_procs([procs])
+            file_output(CAP_NETWORK_STATUS, [OPENVSWITCH_COMPACT_DB])
+        else:
+            file_output(CAP_NETWORK_STATUS, [OPENVSWITCH_CONF_DB])
+    except OSError, e:
+        return
+
+def cleanup_ovsdb():
+    try:
+        if os.path.isfile(OPENVSWITCH_COMPACT_DB):
+            os.unlink(OPENVSWITCH_COMPACT_DB)
+    except:
+        return
+
 def fd_usage(cap):
     output = ''
     fd_dict = {}
index 35a2ca7..899ce4e 100644 (file)
@@ -1941,11 +1941,13 @@ fte_free_all(struct classifier *cls)
     struct cls_cursor cursor;
     struct fte *fte, *next;
 
+    ovs_rwlock_wrlock(&cls->rwlock);
     cls_cursor_init(&cursor, cls, NULL);
     CLS_CURSOR_FOR_EACH_SAFE (fte, next, rule, &cursor) {
         classifier_remove(cls, &fte->rule);
         fte_free(fte);
     }
+    ovs_rwlock_unlock(&cls->rwlock);
     classifier_destroy(cls);
 }
 
@@ -1964,7 +1966,9 @@ fte_insert(struct classifier *cls, const struct match *match,
     cls_rule_init(&fte->rule, match, priority);
     fte->versions[index] = version;
 
+    ovs_rwlock_wrlock(&cls->rwlock);
     old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
+    ovs_rwlock_unlock(&cls->rwlock);
     if (old) {
         fte_version_free(old->versions[index]);
         fte->versions[!index] = old->versions[!index];
@@ -2174,6 +2178,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
     list_init(&requests);
 
     /* Delete flows that exist on the switch but not in the file. */
+    ovs_rwlock_rdlock(&cls.rwlock);
     cls_cursor_init(&cursor, &cls, NULL);
     CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
         struct fte_version *file_ver = fte->versions[FILE_IDX];
@@ -2197,6 +2202,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
             fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests);
         }
     }
+    ovs_rwlock_unlock(&cls.rwlock);
     transact_multiple_noreply(vconn, &requests);
     vconn_close(vconn);
 
@@ -2238,6 +2244,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
     ds_init(&a_s);
     ds_init(&b_s);
 
+    ovs_rwlock_rdlock(&cls.rwlock);
     cls_cursor_init(&cursor, &cls, NULL);
     CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
         struct fte_version *a = fte->versions[0];
@@ -2257,6 +2264,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
             }
         }
     }
+    ovs_rwlock_unlock(&cls.rwlock);
 
     ds_destroy(&a_s);
     ds_destroy(&b_s);
index 9e3d228..ae523f3 100644 (file)
@@ -576,7 +576,7 @@ system_stats_wait(void)
 }
 
 static void
-discard_stats(void) OVS_REQUIRES(&mutex)
+discard_stats(void) OVS_REQUIRES(mutex)
 {
     if (system_stats) {
         smap_destroy(system_stats);