Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / meta-flow.c
index 0677202..8f67b94 100644 (file)
@@ -27,6 +27,7 @@
 #include "dynamic-string.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
+#include "ovs-thread.h"
 #include "packets.h"
 #include "random.h"
 #include "shash.h"
@@ -580,13 +581,17 @@ struct nxm_field {
 };
 
 /* Contains 'struct nxm_field's. */
-static struct hmap all_fields = HMAP_INITIALIZER(&all_fields);
+static struct hmap all_fields;
+
+/* Maps from an mf_field's 'name' or 'extra_name' to the mf_field. */
+static struct shash mf_by_name;
 
 /* Rate limit for parse errors.  These always indicate a bug in an OpenFlow
  * controller and so there's not much point in showing a lot of them. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
 const struct mf_field *mf_from_nxm_header__(uint32_t header);
+static void nxm_init(void);
 
 /* Returns the field with the given 'id'. */
 const struct mf_field *
@@ -601,19 +606,7 @@ mf_from_id(enum mf_field_id id)
 const struct mf_field *
 mf_from_name(const char *name)
 {
-    static struct shash mf_by_name = SHASH_INITIALIZER(&mf_by_name);
-
-    if (shash_is_empty(&mf_by_name)) {
-        const struct mf_field *mf;
-
-        for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) {
-            shash_add_once(&mf_by_name, mf->name, mf);
-            if (mf->extra_name) {
-                shash_add_once(&mf_by_name, mf->extra_name, mf);
-            }
-        }
-    }
-
+    nxm_init();
     return shash_find_data(&mf_by_name, name);
 }
 
@@ -641,24 +634,36 @@ nxm_init_add_field(const struct mf_field *mf, uint32_t header)
 }
 
 static void
-nxm_init(void)
+nxm_do_init(void)
 {
     const struct mf_field *mf;
 
+    hmap_init(&all_fields);
+    shash_init(&mf_by_name);
     for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) {
         nxm_init_add_field(mf, mf->nxm_header);
         if (mf->oxm_header != mf->nxm_header) {
             nxm_init_add_field(mf, mf->oxm_header);
         }
+
+        shash_add_once(&mf_by_name, mf->name, mf);
+        if (mf->extra_name) {
+            shash_add_once(&mf_by_name, mf->extra_name, mf);
+        }
     }
 }
 
+static void
+nxm_init(void)
+{
+    static pthread_once_t once = PTHREAD_ONCE_INIT;
+    pthread_once(&once, nxm_do_init);
+}
+
 const struct mf_field *
 mf_from_nxm_header(uint32_t header)
 {
-    if (hmap_is_empty(&all_fields)) {
-        nxm_init();
-    }
+    nxm_init();
     return mf_from_nxm_header__(header);
 }
 
@@ -2641,7 +2646,7 @@ mf_parse_subfield_name(const char *name, int name_len, bool *wild)
  * bit indexes.  "..end" may be omitted to indicate a single bit.  "start..end"
  * may both be omitted (the [] are still required) to indicate an entire
  * field. */
-char *
+char * WARN_UNUSED_RESULT
 mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
 {
     const struct mf_field *field;
@@ -2696,24 +2701,23 @@ mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
     return NULL;
 }
 
-/* Parses a subfield from the beginning of 's' into 'sf'.  Returns the first
- * byte in 's' following the parsed string.
- *
- * Exits with an error message if 's' has incorrect syntax.
+/* Parses a subfield from the entirety of 's' into 'sf'.  Returns NULL if
+ * successful, otherwise a malloc()'d string describing the error.  The caller
+ * is responsible for freeing the returned string.
  *
  * The syntax parsed from 's' takes the form "header[start..end]" where
  * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive)
  * bit indexes.  "..end" may be omitted to indicate a single bit.  "start..end"
  * may both be omitted (the [] are still required) to indicate an entire
  * field.  */
-const char *
+char * WARN_UNUSED_RESULT
 mf_parse_subfield(struct mf_subfield *sf, const char *s)
 {
-    char *msg = mf_parse_subfield__(sf, &s);
-    if (msg) {
-        ovs_fatal(0, "%s", msg);
+    char *error = mf_parse_subfield__(sf, &s);
+    if (!error && s[0]) {
+        error = xstrdup("unexpected input following field syntax");
     }
-    return s;
+    return error;
 }
 
 void