+\f
+/* Formats 'sf' into 's' in a format normally acceptable to
+ * mf_parse_subfield(). (It won't be acceptable if sf->field is NULL or if
+ * sf->field has no NXM name.) */
+void
+mf_format_subfield(const struct mf_subfield *sf, struct ds *s)
+{
+ if (!sf->field) {
+ ds_put_cstr(s, "<unknown>");
+ } else {
+ const struct nxm_field *f = nxm_field_by_mf_id(sf->field->id, 0);
+ ds_put_cstr(s, f ? f->name : sf->field->name);
+ }
+
+ if (sf->field && sf->ofs == 0 && sf->n_bits == sf->field->n_bits) {
+ ds_put_cstr(s, "[]");
+ } else if (sf->n_bits == 1) {
+ ds_put_format(s, "[%d]", sf->ofs);
+ } else {
+ ds_put_format(s, "[%d..%d]", sf->ofs, sf->ofs + sf->n_bits - 1);
+ }
+}
+
+static const struct nxm_field *
+mf_parse_subfield_name(const char *name, int name_len, bool *wild)
+{
+ *wild = name_len > 2 && !memcmp(&name[name_len - 2], "_W", 2);
+ if (*wild) {
+ name_len -= 2;
+ }
+
+ return nxm_field_by_name(name, name_len);
+}
+
+/* Parses a subfield from the beginning of '*sp' into 'sf'. If successful,
+ * returns NULL and advances '*sp' to the first byte following the parsed
+ * string. On failure, returns a malloc()'d error message, does not modify
+ * '*sp', and does not properly initialize 'sf'.
+ *
+ * The syntax parsed from '*sp' 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. */
+char * OVS_WARN_UNUSED_RESULT
+mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
+{
+ const struct mf_field *field;
+ const struct nxm_field *f;
+ const char *name;
+ int start, end;
+ const char *s;
+ int name_len;
+ bool wild;
+
+ s = *sp;
+ name = s;
+ name_len = strcspn(s, "[");
+ if (s[name_len] != '[') {
+ return xasprintf("%s: missing [ looking for field name", *sp);
+ }
+
+ f = mf_parse_subfield_name(name, name_len, &wild);
+ if (!f) {
+ return xasprintf("%s: unknown field `%.*s'", *sp, name_len, s);
+ }
+ field = mf_from_id(f->id);
+
+ s += name_len;
+ if (ovs_scan(s, "[%d..%d]", &start, &end)) {
+ /* Nothing to do. */
+ } else if (ovs_scan(s, "[%d]", &start)) {
+ end = start;
+ } else if (!strncmp(s, "[]", 2)) {
+ start = 0;
+ end = field->n_bits - 1;
+ } else {
+ return xasprintf("%s: syntax error expecting [] or [<bit>] or "
+ "[<start>..<end>]", *sp);
+ }
+ s = strchr(s, ']') + 1;
+
+ if (start > end) {
+ return xasprintf("%s: starting bit %d is after ending bit %d",
+ *sp, start, end);
+ } else if (start >= field->n_bits) {
+ return xasprintf("%s: starting bit %d is not valid because field is "
+ "only %d bits wide", *sp, start, field->n_bits);
+ } else if (end >= field->n_bits){
+ return xasprintf("%s: ending bit %d is not valid because field is "
+ "only %d bits wide", *sp, end, field->n_bits);
+ }
+
+ sf->field = field;
+ sf->ofs = start;
+ sf->n_bits = end - start + 1;
+
+ *sp = s;
+ return NULL;
+}
+
+/* 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. */
+char * OVS_WARN_UNUSED_RESULT
+mf_parse_subfield(struct mf_subfield *sf, const char *s)
+{
+ char *error = mf_parse_subfield__(sf, &s);
+ if (!error && s[0]) {
+ error = xstrdup("unexpected input following field syntax");
+ }
+ return error;
+}
+\f
+/* Returns an bitmap in which each bit corresponds to the like-numbered field
+ * in the OFPXMC12_OPENFLOW_BASIC OXM class, in which the bit values are taken
+ * from the 'fields' bitmap. Only fields defined in OpenFlow 'version' are
+ * considered.
+ *
+ * This is useful for encoding OpenFlow 1.2 table stats messages. */
+ovs_be64
+oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *fields,
+ enum ofp_version version)
+{
+ uint64_t oxm_bitmap = 0;
+ int i;
+
+ BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fields->bm) {
+ uint64_t oxm = mf_oxm_header(i, version);
+ uint32_t class = nxm_class(oxm);
+ int field = nxm_field(oxm);
+
+ if (class == OFPXMC12_OPENFLOW_BASIC && field < 64) {
+ oxm_bitmap |= UINT64_C(1) << field;
+ }
+ }
+ return htonll(oxm_bitmap);
+}
+
+/* Opposite conversion from oxm_bitmap_from_mf_bitmap().
+ *
+ * This is useful for decoding OpenFlow 1.2 table stats messages. */
+struct mf_bitmap
+oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap, enum ofp_version version)
+{
+ struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
+
+ for (enum mf_field_id id = 0; id < MFF_N_IDS; id++) {
+ uint64_t oxm = mf_oxm_header(id, version);
+ if (oxm && version >= nxm_field_by_header(oxm)->version) {
+ uint32_t class = nxm_class(oxm);
+ int field = nxm_field(oxm);
+
+ if (class == OFPXMC12_OPENFLOW_BASIC
+ && field < 64
+ && oxm_bitmap & htonll(UINT64_C(1) << field)) {
+ bitmap_set1(fields.bm, id);
+ }
+ }
+ }
+ return fields;
+}
+
+/* Returns a bitmap of fields that can be encoded in OXM and that can be
+ * modified with a "set_field" action. */
+struct mf_bitmap
+oxm_writable_fields(void)
+{
+ struct mf_bitmap b = MF_BITMAP_INITIALIZER;
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (mf_oxm_header(i, 0) && mf_from_id(i)->writable) {
+ bitmap_set1(b.bm, i);
+ }
+ }
+ return b;
+}
+
+/* Returns a bitmap of fields that can be encoded in OXM and that can be
+ * matched in a flow table. */
+struct mf_bitmap
+oxm_matchable_fields(void)
+{
+ struct mf_bitmap b = MF_BITMAP_INITIALIZER;
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (mf_oxm_header(i, 0)) {
+ bitmap_set1(b.bm, i);
+ }
+ }
+ return b;
+}
+
+/* Returns a bitmap of fields that can be encoded in OXM and that can be
+ * matched in a flow table with an arbitrary bitmask. */
+struct mf_bitmap
+oxm_maskable_fields(void)
+{
+ struct mf_bitmap b = MF_BITMAP_INITIALIZER;
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (mf_oxm_header(i, 0) && mf_from_id(i)->maskable == MFM_FULLY) {
+ bitmap_set1(b.bm, i);
+ }
+ }
+ return b;
+}
+\f
+struct nxm_field_index {
+ struct hmap_node header_node; /* In nxm_header_map. */
+ struct hmap_node name_node; /* In nxm_name_map. */
+ struct ovs_list mf_node; /* In mf_mf_map[nf.id]. */
+ const struct nxm_field nf;
+};
+
+#include "nx-match.inc"
+
+static struct hmap nxm_header_map;
+static struct hmap nxm_name_map;
+static struct ovs_list nxm_mf_map[MFF_N_IDS];
+
+static void
+nxm_init(void)
+{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+ if (ovsthread_once_start(&once)) {
+ hmap_init(&nxm_header_map);
+ hmap_init(&nxm_name_map);
+ for (int i = 0; i < MFF_N_IDS; i++) {
+ list_init(&nxm_mf_map[i]);
+ }
+ for (struct nxm_field_index *nfi = all_nxm_fields;
+ nfi < &all_nxm_fields[ARRAY_SIZE(all_nxm_fields)]; nfi++) {
+ hmap_insert(&nxm_header_map, &nfi->header_node,
+ hash_uint64(nxm_no_len(nfi->nf.header)));
+ hmap_insert(&nxm_name_map, &nfi->name_node,
+ hash_string(nfi->nf.name, 0));
+ list_push_back(&nxm_mf_map[nfi->nf.id], &nfi->mf_node);
+ }
+ ovsthread_once_done(&once);
+ }
+}
+
+static const struct nxm_field *
+nxm_field_by_header(uint64_t header)
+{
+ const struct nxm_field_index *nfi;
+ uint64_t header_no_len;
+
+ nxm_init();
+ if (nxm_hasmask(header)) {
+ header = nxm_make_exact_header(header);
+ }
+
+ header_no_len = nxm_no_len(header);
+
+ HMAP_FOR_EACH_IN_BUCKET (nfi, header_node, hash_uint64(header_no_len),
+ &nxm_header_map) {
+ if (header_no_len == nxm_no_len(nfi->nf.header)) {
+ if (nxm_length(header) == nxm_length(nfi->nf.header) ||
+ mf_from_id(nfi->nf.id)->variable_len) {
+ return &nfi->nf;
+ } else {
+ return NULL;
+ }
+ }
+ }
+ return NULL;
+}
+
+static const struct nxm_field *
+nxm_field_by_name(const char *name, size_t len)
+{
+ const struct nxm_field_index *nfi;
+
+ nxm_init();
+ HMAP_FOR_EACH_WITH_HASH (nfi, name_node, hash_bytes(name, len, 0),
+ &nxm_name_map) {
+ if (strlen(nfi->nf.name) == len && !memcmp(nfi->nf.name, name, len)) {
+ return &nfi->nf;
+ }
+ }
+ return NULL;
+}
+
+static const struct nxm_field *
+nxm_field_by_mf_id(enum mf_field_id id, enum ofp_version version)
+{
+ const struct nxm_field_index *nfi;
+ const struct nxm_field *f;
+
+ nxm_init();
+
+ f = NULL;
+ LIST_FOR_EACH (nfi, mf_node, &nxm_mf_map[id]) {
+ if (!f || version >= nfi->nf.version) {
+ f = &nfi->nf;
+ }
+ }
+ return f;
+}