nx-match: Move all knowledge of OXM/NXM here.
authorBen Pfaff <blp@nicira.com>
Wed, 17 Sep 2014 05:13:44 +0000 (22:13 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 7 Oct 2014 22:34:38 +0000 (15:34 -0700)
This improves the general abstraction of OXM/NXM by eliminating direct
knowledge of it from the meta-flow code and other places.

Some function renaming might be called for; for example, mf_oxm_header()
may not be the best name now that the function is implemented within
nx-match.  However, these renamings would make this commit larger and
harder to review, so I'm postponing them.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
14 files changed:
build-aux/extract-ofp-fields
include/openflow/nicira-ext.h
include/openflow/openflow-1.2.h
lib/automake.mk
lib/meta-flow.c
lib/meta-flow.h
lib/nx-match.c
lib/nx-match.h
lib/ofp-actions.c
lib/ofp-util.c
ofproto/ofproto.c
tests/ofp-actions.at
tests/ovs-ofctl.at
vswitchd/bridge.c

index 5543647..a82606b 100755 (executable)
@@ -94,10 +94,11 @@ def usage():
     argv0 = os.path.basename(sys.argv[0])
     print '''\
 %(argv0)s, for extracting OpenFlow field properties from meta-flow.h
-usage: %(argv0)s INPUT
+usage: %(argv0)s INPUT [--meta-flow | --nx-match]
   where INPUT points to lib/meta-flow.h in the source directory.
-The output written to stdout is intended to be saved as lib/meta-flow.inc,
-which lib/meta-flow.c \"#include\"s.\
+Depending on the option given, the output written to stdout is intended to be
+saved either as lib/meta-flow.inc or lib/nx-match.inc for the respective C
+file to #include.\
 ''' % {"argv0": argv0}
     sys.exit(0)
 
@@ -122,7 +123,7 @@ def parse_oxm(s, prefix, n_bytes):
     class_ = oxm_name_to_class(name)
     if class_ is None:
         fatal("unknown OXM class for %s" % name)
-    header = ("NXM_HEADER(0x%04x, %s, %d)" % (class_, code, n_bytes))
+    header = ("NXM_HEADER(0x%04x,%s,0,%d)" % (class_, code, n_bytes))
 
     if of_version:
         if of_version not in VERSION:
@@ -244,7 +245,97 @@ def protocols_to_c(protocols):
     else:
         assert False        
 
-def extract_ofp_fields():
+def make_meta_flow(fields):
+    output = []
+    for f in fields:
+        output += ["{"]
+        output += ["    %s," % f['mff']]
+        if f['extra_name']:
+            output += ["    \"%s\", \"%s\"," % (f['name'], f['extra_name'])]
+        else:
+            output += ["    \"%s\", NULL," % f['name']]
+        output += ["    %d, %d," % (f['n_bytes'], f['n_bits'])]
+
+        if f['writable']:
+            rw = 'true'
+        else:
+            rw = 'false'
+        output += ["    %s, %s, %s, %s,"
+                   % (f['mask'], f['string'], f['prereqs'], rw)]
+
+        nxm = f['NXM']
+        oxm = f['OXM']
+        if not nxm:
+            nxm = oxm
+        elif not oxm:
+            oxm = nxm
+
+        of10 = f['OF1.0']
+        of11 = f['OF1.1']
+        if f['mff'] in ('MFF_DL_VLAN', 'MFF_DL_VLAN_PCP'):
+            # MFF_DL_VLAN and MFF_DL_VLAN_PCP don't exactly correspond to
+            # OF1.1, nor do they have NXM or OXM assignments, but their
+            # meanings can be expressed in every protocol, which is the goal of
+            # this member.
+            protocols = set(["of10", "of11", "oxm"])
+        else:
+            protocols = set([])
+            if of10:
+                protocols |= set(["of10"])
+            if of11:
+                protocols |= set(["of11"])
+            if nxm or oxm:
+                protocols |= set(["oxm"])
+
+        if f['mask'] == 'MFM_FULLY':
+            cidr_protocols = protocols.copy()
+            bitwise_protocols = protocols.copy()
+
+            if of10 == 'exact match':
+                bitwise_protocols -= set(['of10'])
+                cidr_protocols -= set(['of10'])
+            elif of10 == 'CIDR mask':
+                bitwise_protocols -= set(['of10'])
+            else:
+                assert of10 is None
+
+            if of11 == 'exact match':
+                bitwise_protocols -= set(['of11'])
+                cidr_protocols -= set(['of11'])
+            else:
+                assert of11 in (None, 'bitwise mask')
+        else:
+            assert f['mask'] == 'MFM_NONE'
+            cidr_protocols = set([])
+            bitwise_protocols = set([])
+
+        output += ["    %s," % protocols_to_c(protocols)]
+        output += ["    %s," % protocols_to_c(cidr_protocols)]
+        output += ["    %s," % protocols_to_c(bitwise_protocols)]
+        
+        if f['prefix']:
+            output += ["    FLOW_U32OFS(%s)," % f['prefix']]
+        else:
+            output += ["    -1, /* not usable for prefix lookup */"]
+
+        output += ["},"]
+    return output
+
+def print_oxm_field(oxm, mff):
+    if oxm:
+        print """{ .nf = { %s, %d, "%s", %s } },""" % (
+            oxm[0], oxm[2], oxm[1], mff)
+
+def make_nx_match(fields):
+    output = []
+    print "static struct nxm_field_index all_nxm_fields[] = {";
+    for f in fields:
+        print_oxm_field(f['NXM'], f['mff'])
+        print_oxm_field(f['OXM'], f['mff'])
+    print "};"
+    return output
+
+def extract_ofp_fields(mode):
     global line
 
     fields = []
@@ -349,91 +440,16 @@ def extract_ofp_fields():
     if n_errors:
         sys.exit(1)
 
-    output = []
-    output += ["/* Generated automatically; do not modify!     "
-               "-*- buffer-read-only: t -*- */"]
-    output += [""]
-
-    for f in fields:
-        output += ["{"]
-        output += ["    %s," % f['mff']]
-        if f['extra_name']:
-            output += ["    \"%s\", \"%s\"," % (f['name'], f['extra_name'])]
-        else:
-            output += ["    \"%s\", NULL," % f['name']]
-        output += ["    %d, %d," % (f['n_bytes'], f['n_bits'])]
-
-        if f['writable']:
-            rw = 'true'
-        else:
-            rw = 'false'
-        output += ["    %s, %s, %s, %s,"
-                   % (f['mask'], f['string'], f['prereqs'], rw)]
-
-        nxm = f['NXM']
-        oxm = f['OXM']
-        if not nxm:
-            nxm = oxm
-        elif not oxm:
-            oxm = nxm
-        if nxm:
-            output += ["    %s, \"%s\"," % (nxm[0], nxm[1])]
-            output += ["    %s, \"%s\", %s," % (oxm[0], oxm[1], oxm[2])]
-        else:
-            output += ["    0, NULL, 0, NULL, 0, /* no NXM or OXM */"]
-
-        of10 = f['OF1.0']
-        of11 = f['OF1.1']
-        if f['mff'] in ('MFF_DL_VLAN', 'MFF_DL_VLAN_PCP'):
-            # MFF_DL_VLAN and MFF_DL_VLAN_PCP don't exactly correspond to
-            # OF1.1, nor do they have NXM or OXM assignments, but their
-            # meanings can be expressed in every protocol, which is the goal of
-            # this member.
-            protocols = set(["of10", "of11", "oxm"])
-        else:
-            protocols = set([])
-            if of10:
-                protocols |= set(["of10"])
-            if of11:
-                protocols |= set(["of11"])
-            if nxm or oxm:
-                protocols |= set(["oxm"])
+    print """\
+/* Generated automatically; do not modify!    "-*- buffer-read-only: t -*- */
+"""
 
-        if f['mask'] == 'MFM_FULLY':
-            cidr_protocols = protocols.copy()
-            bitwise_protocols = protocols.copy()
-
-            if of10 == 'exact match':
-                bitwise_protocols -= set(['of10'])
-                cidr_protocols -= set(['of10'])
-            elif of10 == 'CIDR mask':
-                bitwise_protocols -= set(['of10'])
-            else:
-                assert of10 is None
-
-            if of11 == 'exact match':
-                bitwise_protocols -= set(['of11'])
-                cidr_protocols -= set(['of11'])
-            else:
-                assert of11 in (None, 'bitwise mask')
-        else:
-            assert f['mask'] == 'MFM_NONE'
-            cidr_protocols = set([])
-            bitwise_protocols = set([])
-
-        output += ["    %s," % protocols_to_c(protocols)]
-        output += ["    %s," % protocols_to_c(cidr_protocols)]
-        output += ["    %s," % protocols_to_c(bitwise_protocols)]
-        
-        if f['prefix']:
-            output += ["    FLOW_U32OFS(%s)," % f['prefix']]
-        else:
-            output += ["    -1, /* not usable for prefix lookup */"]
-
-        output += ["},"]
-
-    if n_errors:
-        sys.exit(1)
+    if mode == '--meta-flow':
+        output = make_meta_flow(fields)
+    elif mode == '--nx-match':
+        output = make_nx_match(fields)
+    else:
+        assert False
 
     return output
 
@@ -441,11 +457,11 @@ def extract_ofp_fields():
 if __name__ == '__main__':
     if '--help' in sys.argv:
         usage()
-    elif len(sys.argv) != 2:
-        sys.stderr.write("exactly one non-option argument required; "
+    elif len(sys.argv) != 3:
+        sys.stderr.write("exactly two arguments required; "
                          "use --help for help\n")
         sys.exit(1)
-    else:
+    elif sys.argv[2] in ('--meta-flow', '--nx-match'):
         global file_name
         global input_file
         global line_number
@@ -453,6 +469,10 @@ if __name__ == '__main__':
         input_file = open(file_name)
         line_number = 0
 
-        for oline in extract_ofp_fields():
+        for oline in extract_ofp_fields(sys.argv[2]):
             print oline
+    else:
+        sys.stderr.write("invalid arguments; use --help for help\n")
+        sys.exit(1)
+
         
index b1885b2..65ba950 100644 (file)
@@ -467,21 +467,6 @@ OFP_ASSERT(sizeof(struct nx_async_config) == 24);
  * nx_match error.
  */
 
-#define NXM_HEADER__(VENDOR, FIELD, HASMASK, LENGTH) \
-    (((VENDOR) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH))
-#define NXM_HEADER(VENDOR, FIELD, LENGTH) \
-    NXM_HEADER__(VENDOR, FIELD, 0, LENGTH)
-#define NXM_HEADER_W(VENDOR, FIELD, LENGTH) \
-    NXM_HEADER__(VENDOR, FIELD, 1, (LENGTH) * 2)
-#define NXM_VENDOR(HEADER) ((HEADER) >> 16)
-#define NXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f)
-#define NXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff)
-#define NXM_HASMASK(HEADER) (((HEADER) >> 8) & 1)
-#define NXM_LENGTH(HEADER) ((HEADER) & 0xff)
-
-#define NXM_MAKE_WILD_HEADER(HEADER) \
-        NXM_HEADER_W(NXM_VENDOR(HEADER), NXM_FIELD(HEADER), NXM_LENGTH(HEADER))
-
 /* Number of registers allocated NXM field IDs. */
 #define NXM_NX_MAX_REGS 16
 
@@ -489,23 +474,6 @@ OFP_ASSERT(sizeof(struct nx_async_config) == 24);
 #define NX_IP_FRAG_ANY   (1 << 0) /* Is this a fragment? */
 #define NX_IP_FRAG_LATER (1 << 1) /* Is this a fragment with nonzero offset? */
 
-/* Flow cookie.
- *
- * This may be used to gain the OpenFlow 1.1-like ability to restrict
- * certain NXM-based Flow Mod and Flow Stats Request messages to flows
- * with specific cookies.  See the "nx_flow_mod" and "nx_flow_stats_request"
- * structure definitions for more details.  This match is otherwise not
- * allowed.
- *
- * Prereqs: None.
- *
- * Format: 64-bit integer in network byte order.
- *
- * Masking: Arbitrary masks. */
-#define NXM_NX_COOKIE     NXM_HEADER  (0x0001, 30, 8)
-#define NXM_NX_COOKIE_W   NXM_HEADER_W(0x0001, 30, 8)
-
-
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
 /* ## --------------------- ## */
index ef1d340..f4c97a1 100644 (file)
 /* Error type for experimenter error messages. */
 #define OFPET12_EXPERIMENTER 0xffff
 
-/*
- * OXM Class IDs.
- * The high order bit differentiate reserved classes from member classes.
- * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
- * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
- */
-enum ofp12_oxm_class {
-    OFPXMC12_NXM_0          = 0x0000, /* Backward compatibility with NXM */
-    OFPXMC12_NXM_1          = 0x0001, /* Backward compatibility with NXM */
-    OFPXMC12_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */
-    OFPXMC15_PACKET_REGS    = 0x8001, /* Packet registers (pipeline fields). */
-    OFPXMC12_EXPERIMENTER   = 0xffff, /* Experimenter class */
-};
-
-#define IS_OXM_HEADER(header) (NXM_VENDOR(header) == OFPXMC12_OPENFLOW_BASIC)
-
 /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
  * special conditions.
  */
index 329eca7..ec4ad8e 100644 (file)
@@ -444,9 +444,12 @@ lib/dirs.c: lib/dirs.c.in Makefile
        mv lib/dirs.c.tmp lib/dirs.c
 
 lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields lib/meta-flow.h
-       $(AM_V_GEN)$(run_python) $^ > $@.tmp && mv $@.tmp $@
+       $(AM_V_GEN)$(run_python) $^ --meta-flow > $@.tmp && mv $@.tmp $@
 lib/meta-flow.lo: lib/meta-flow.inc
-CLEANFILES += lib/meta-flow.inc
+lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields lib/meta-flow.h
+       $(AM_V_GEN)$(run_python) $^ --nx-match > $@.tmp && mv $@.tmp $@
+lib/nx-match.lo: lib/nx-match.inc
+CLEANFILES += lib/meta-flow.inc lib/nx-match.inc
 EXTRA_DIST += build-aux/extract-ofp-fields
 
 lib/ofp-actions.inc1: $(srcdir)/build-aux/extract-ofp-actions lib/ofp-actions.c
index b59aae7..5056be5 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "classifier.h"
 #include "dynamic-string.h"
+#include "nx-match.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
 #include "ovs-thread.h"
@@ -50,16 +51,6 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
 #include "meta-flow.inc"
 };
 
-/* Maps an NXM or OXM header value to an mf_field. */
-struct nxm_field {
-    struct hmap_node hmap_node; /* In 'all_fields' hmap. */
-    uint32_t header;            /* NXM or OXM header value. */
-    const struct mf_field *mf;
-};
-
-/* Contains 'struct nxm_field's. */
-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;
 
@@ -67,7 +58,6 @@ static struct shash mf_by_name;
  * 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 'name', or a null pointer if no field has
@@ -79,46 +69,17 @@ mf_from_name(const char *name)
     return shash_find_data(&mf_by_name, name);
 }
 
-static void
-add_nxm_field(uint32_t header, const struct mf_field *mf)
-{
-    struct nxm_field *f;
-
-    f = xmalloc(sizeof *f);
-    hmap_insert(&all_fields, &f->hmap_node, hash_int(header, 0));
-    f->header = header;
-    f->mf = mf;
-}
-
-static void
-nxm_init_add_field(const struct mf_field *mf, uint32_t header)
-{
-    if (header) {
-        ovs_assert(!mf_from_nxm_header__(header));
-        add_nxm_field(header, mf);
-        if (mf->maskable != MFM_NONE) {
-            add_nxm_field(NXM_MAKE_WILD_HEADER(header), mf);
-        }
-    }
-}
-
 static void
 nxm_do_init(void)
 {
     int i;
 
-    hmap_init(&all_fields);
     shash_init(&mf_by_name);
     for (i = 0; i < MFF_N_IDS; i++) {
         const struct mf_field *mf = &mf_fields[i];
 
         ovs_assert(mf->id == i); /* Fields must be in the enum order. */
 
-        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);
@@ -133,37 +94,6 @@ nxm_init(void)
     pthread_once(&once, nxm_do_init);
 }
 
-const struct mf_field *
-mf_from_nxm_header(uint32_t header)
-{
-    nxm_init();
-    return mf_from_nxm_header__(header);
-}
-
-const struct mf_field *
-mf_from_nxm_header__(uint32_t header)
-{
-    const struct nxm_field *f;
-
-    HMAP_FOR_EACH_IN_BUCKET (f, hmap_node, hash_int(header, 0), &all_fields) {
-        if (f->header == header) {
-            return f->mf;
-        }
-    }
-
-    return NULL;
-}
-
-uint32_t
-mf_oxm_header(enum mf_field_id id, enum ofp_version oxm_version)
-{
-    const struct mf_field *field = mf_from_id(id);
-
-    return (oxm_version >= field->oxm_version
-            ? field->oxm_header
-            : field->nxm_header);
-}
-
 /* Returns true if 'wc' wildcards all the bits in field 'mf', false if 'wc'
  * specifies at least one bit in the field.
  *
@@ -2230,144 +2160,6 @@ mf_get_subfield(const struct mf_subfield *sf, const struct flow *flow)
     return bitwise_get(&value, sf->field->n_bytes, sf->ofs, sf->n_bits);
 }
 
-/* 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 if (sf->field->nxm_name) {
-        ds_put_cstr(s, sf->field->nxm_name);
-    } else if (sf->field->nxm_header) {
-        uint32_t header = sf->field->nxm_header;
-        ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
-    } else {
-        ds_put_cstr(s, 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 mf_field *
-mf_parse_subfield_name(const char *name, int name_len, bool *wild)
-{
-    int i;
-
-    *wild = name_len > 2 && !memcmp(&name[name_len - 2], "_W", 2);
-    if (*wild) {
-        name_len -= 2;
-    }
-
-    for (i = 0; i < MFF_N_IDS; i++) {
-        const struct mf_field *mf = mf_from_id(i);
-
-        if (mf->nxm_name
-            && !strncmp(mf->nxm_name, name, name_len)
-            && mf->nxm_name[name_len] == '\0') {
-            return mf;
-        }
-        if (mf->oxm_name
-            && !strncmp(mf->oxm_name, name, name_len)
-            && mf->oxm_name[name_len] == '\0') {
-            return mf;
-        }
-    }
-
-    return NULL;
-}
-
-/* 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 * WARN_UNUSED_RESULT
-mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
-{
-    const struct mf_field *field;
-    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);
-    }
-
-    field = mf_parse_subfield_name(name, name_len, &wild);
-    if (!field) {
-        return xasprintf("%s: unknown field `%.*s'", *sp, name_len, s);
-    }
-
-    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 * 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;
-}
-
 void
 mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
 {
index 2dd087a..7cdacca 100644 (file)
@@ -1448,39 +1448,6 @@ struct mf_field {
     enum mf_prereqs prereqs;
     bool writable;              /* May be written by actions? */
 
-    /* NXM and OXM properties.
-     *
-     * There are the following possibilities for these members for a given
-     * mf_field:
-     *
-     *   - Neither NXM nor OXM defines such a field: these members will all be
-     *     zero or NULL.
-     *
-     *   - NXM and OXM both define such a field: nxm_header and oxm_header will
-     *     both be nonzero and different, similarly for nxm_name and oxm_name.
-     *     In this case, 'oxm_version' is significant: if it is greater than
-     *     OFP12_VERSION, then only that version of OpenFlow introduced this
-     *     OXM header, so ovs-vswitchd should send 'nxm_header' instead with
-     *     earlier protocol versions to avoid confusing controllers that were
-     *     using a previous Open vSwitch extension.
-     *
-     *   - Only NXM or only OXM defines such a field: nxm_header and oxm_header
-     *     will both have the same value (either an OXM_* or NXM_* value) and
-     *     similarly for nxm_name and oxm_name.
-     *
-     * Thus, 'nxm_header' is the appropriate header to use when outputting an
-     * NXM formatted match, since it will be an NXM_* constant when possible
-     * for compatibility with OpenFlow implementations that expect that, with
-     * OXM_* constants used for fields that OXM adds.  Conversely, 'oxm_header'
-     * is the header to use when outputting an OXM formatted match to an
-     * OpenFlow connection of version 'oxm_version' or above (and otherwise
-     * 'nxm_header'). */
-    uint32_t nxm_header;        /* An NXM_* (or OXM_*) constant. */
-    const char *nxm_name;       /* The nxm_header constant's name. */
-    uint32_t oxm_header;        /* An OXM_* (or NXM_*) constant. */
-    const char *oxm_name;       /* The oxm_header constant's name */
-    enum ofp_version oxm_version; /* OpenFlow version that added oxm_header. */
-
     /* Usable protocols.
      *
      * NXM and OXM are extensible, allowing later extensions to be sent in
@@ -1536,8 +1503,6 @@ BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue));
 
 /* Finding mf_fields. */
 const struct mf_field *mf_from_name(const char *name);
-const struct mf_field *mf_from_nxm_header(uint32_t nxm_header);
-const struct mf_field *mf_from_nxm_name(const char *nxm_name);
 
 static inline const struct mf_field *
 mf_from_id(enum mf_field_id id)
@@ -1547,9 +1512,6 @@ mf_from_id(enum mf_field_id id)
     return &mf_fields[id];
 }
 
-/* NXM and OXM protocol headers. */
-uint32_t mf_oxm_header(enum mf_field_id, enum ofp_version oxm_version);
-
 /* Inspecting wildcarded bits. */
 bool mf_is_all_wild(const struct mf_field *, const struct flow_wildcards *);
 
@@ -1601,12 +1563,6 @@ void mf_read_subfield(const struct mf_subfield *, const struct flow *,
 uint64_t mf_get_subfield(const struct mf_subfield *, const struct flow *);
 
 
-void mf_format_subfield(const struct mf_subfield *, struct ds *);
-char *mf_parse_subfield__(struct mf_subfield *sf, const char **s)
-    WARN_UNUSED_RESULT;
-char *mf_parse_subfield(struct mf_subfield *, const char *s)
-    WARN_UNUSED_RESULT;
-
 enum ofperr mf_check_src(const struct mf_subfield *, const struct flow *);
 enum ofperr mf_check_dst(const struct mf_subfield *, const struct flow *);
 
index 4b9a9c4..38233db 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "classifier.h"
 #include "dynamic-string.h"
+#include "hmap.h"
 #include "meta-flow.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
 #include "ofpbuf.h"
 #include "openflow/nicira-ext.h"
 #include "packets.h"
+#include "shash.h"
 #include "unaligned.h"
 #include "util.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(nx_match);
 
+/*
+ * OXM Class IDs.
+ * The high order bit differentiate reserved classes from member classes.
+ * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
+ * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
+ */
+enum ofp12_oxm_class {
+    OFPXMC12_NXM_0          = 0x0000, /* Backward compatibility with NXM */
+    OFPXMC12_NXM_1          = 0x0001, /* Backward compatibility with NXM */
+    OFPXMC12_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */
+    OFPXMC15_PACKET_REGS    = 0x8001, /* Packet registers (pipeline fields). */
+    OFPXMC12_EXPERIMENTER   = 0xffff, /* Experimenter class */
+};
+
+/* Functions for extracting fields from OXM/NXM headers. */
+static int nxm_vendor(uint32_t header) { return header >> 16; }
+static int nxm_field(uint32_t header) { return (header >> 9) & 0x7f; }
+static bool nxm_hasmask(uint32_t header) { return (header & 0x100) != 0; }
+static int nxm_length(uint32_t header) { return header & 0xff; }
+
+/* Returns true if 'header' is a legacy NXM header, false if it is an OXM
+ * header.*/
+static bool
+is_nxm_header(uint32_t header)
+{
+    return nxm_vendor(header) <= 1;
+}
+
+#define NXM_HEADER(VENDOR, FIELD, HASMASK, LENGTH)                      \
+    (((VENDOR) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH))
+
+#define NXM_HEADER_FMT "%d:%d:%d:%d"
+#define NXM_HEADER_ARGS(HEADER)                 \
+    nxm_vendor(HEADER), nxm_field(HEADER),      \
+    nxm_hasmask(HEADER), nxm_length(HEADER)
+
+/* Functions for turning the "hasmask" bit on or off.  (This also requires
+ * adjusting the length.) */
+static uint32_t
+nxm_make_exact_header(uint32_t header)
+{
+    return NXM_HEADER(nxm_vendor(header), nxm_field(header), 0,
+                      nxm_length(header) / 2);
+}
+static uint32_t
+nxm_make_wild_header(uint32_t header)
+{
+    return NXM_HEADER(nxm_vendor(header), nxm_field(header), 1,
+                      nxm_length(header) * 2);
+}
+
+/* Flow cookie.
+ *
+ * This may be used to gain the OpenFlow 1.1-like ability to restrict
+ * certain NXM-based Flow Mod and Flow Stats Request messages to flows
+ * with specific cookies.  See the "nx_flow_mod" and "nx_flow_stats_request"
+ * structure definitions for more details.  This match is otherwise not
+ * allowed. */
+#define NXM_NX_COOKIE     NXM_HEADER  (0x0001, 30, 0, 8)
+#define NXM_NX_COOKIE_W   nxm_make_wild_header(NXM_NX_COOKIE)
+
+struct nxm_field {
+    uint32_t header;
+    enum ofp_version version;
+    const char *name;           /* e.g. "NXM_OF_IN_PORT". */
+
+    enum mf_field_id id;
+};
+
+static const struct nxm_field *nxm_field_by_header(uint32_t header);
+static const struct nxm_field *nxm_field_by_name(const char *name, size_t len);
+static const struct nxm_field *nxm_field_by_mf_id(enum mf_field_id);
+static const struct nxm_field *oxm_field_by_mf_id(enum mf_field_id);
+
 /* Rate limit for nx_match parse errors.  These always indicate a bug in the
  * peer 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);
 
+static const struct nxm_field *
+mf_parse_subfield_name(const char *name, int name_len, bool *wild);
+
+static const struct nxm_field *
+nxm_field_from_mf_field(enum mf_field_id id, enum ofp_version version)
+{
+    const struct nxm_field *oxm = oxm_field_by_mf_id(id);
+    const struct nxm_field *nxm = nxm_field_by_mf_id(id);
+    return oxm && (version >= oxm->version || !nxm) ? oxm : nxm;
+}
+
+/* Returns the preferred OXM header to use for field 'id' in OpenFlow version
+ * 'version'.  Specify 0 for 'version' if an NXM legacy header should be
+ * preferred over any standardized OXM header.  Returns 0 if field 'id' cannot
+ * be expressed in NXM or OXM. */
+uint32_t
+mf_oxm_header(enum mf_field_id id, enum ofp_version version)
+{
+    const struct nxm_field *f = nxm_field_from_mf_field(id, version);
+    return f ? f->header : 0;
+}
+
+/* Returns the "struct mf_field" that corresponds to NXM or OXM header
+ * 'header', or NULL if 'header' doesn't correspond to any known field.  */
+const struct mf_field *
+mf_from_nxm_header(uint32_t header)
+{
+    const struct nxm_field *f = nxm_field_by_header(header);
+    return f ? mf_from_id(f->id) : NULL;
+}
+
 /* Returns the width of the data for a field with the given 'header', in
  * bytes. */
-int
+static int
 nxm_field_bytes(uint32_t header)
 {
-    unsigned int length = NXM_LENGTH(header);
-    return NXM_HASMASK(header) ? length / 2 : length;
+    unsigned int length = nxm_length(header);
+    return nxm_hasmask(header) ? length / 2 : length;
 }
 
-/* Returns the width of the data for a field with the given 'header', in
- * bits. */
-int
-nxm_field_bits(uint32_t header)
+/* Returns the earliest version of OpenFlow that standardized an OXM header for
+ * field 'id', or UINT8_MAX if no version of OpenFlow does. */
+static enum ofp_version
+mf_oxm_version(enum mf_field_id id)
 {
-    return nxm_field_bytes(header) * 8;
+    const struct nxm_field *oxm = oxm_field_by_mf_id(id);
+    return oxm ? oxm->version : UINT8_MAX;
 }
-\f
\f
 /* nx_pull_match() and helpers. */
 
-static uint32_t
-nx_entry_ok(const void *p, unsigned int match_len)
+/* Given NXM/OXM value 'value' and mask 'mask' associated with 'header', checks
+ * for any 1-bit in the value where there is a 0-bit in the mask.  Returns 0 if
+ * none, otherwise an error code. */
+static bool
+is_mask_consistent(uint32_t header, const uint8_t *value, const uint8_t *mask)
 {
-    unsigned int payload_len;
-    ovs_be32 header_be;
-    uint32_t header;
+    unsigned int width = nxm_field_bytes(header);
+    unsigned int i;
 
-    if (match_len < 4) {
-        if (match_len) {
-            VLOG_DBG_RL(&rl, "nx_match ends with partial (%u-byte) nxm_header",
-                        match_len);
+    for (i = 0; i < width; i++) {
+        if (value[i] & ~mask[i]) {
+            if (!VLOG_DROP_WARN(&rl)) {
+                VLOG_WARN_RL(&rl, "Rejecting NXM/OXM entry "NXM_HEADER_FMT " "
+                             "with 1-bits in value for bits wildcarded by the "
+                             "mask.", NXM_HEADER_ARGS(header));
+            }
+            return false;
         }
-        return 0;
     }
-    memcpy(&header_be, p, 4);
-    header = ntohl(header_be);
+    return true;
+}
 
-    payload_len = NXM_LENGTH(header);
-    if (!payload_len) {
-        VLOG_DBG_RL(&rl, "nxm_entry %08"PRIx32" has invalid payload "
-                    "length 0", header);
-        return 0;
+static bool
+is_cookie_pseudoheader(uint32_t header)
+{
+    return header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W;
+}
+
+static enum ofperr
+nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint32_t *header,
+                 const struct mf_field **field)
+{
+    if (ofpbuf_size(b) < 4) {
+        VLOG_DBG_RL(&rl, "encountered partial (%"PRIu32"-byte) OXM entry",
+                    ofpbuf_size(b));
+        goto error;
     }
-    if (match_len < payload_len + 4) {
-        VLOG_DBG_RL(&rl, "%"PRIu32"-byte nxm_entry but only "
-                    "%u bytes left in nx_match", payload_len + 4, match_len);
-        return 0;
+    *header = ntohl(get_unaligned_be32(ofpbuf_pull(b, 4)));
+    if (nxm_length(*header) == 0) {
+        VLOG_WARN_RL(&rl, "OXM header "NXM_HEADER_FMT" has zero length",
+                     NXM_HEADER_ARGS(*header));
+        goto error;
+    }
+    if (field) {
+        *field = mf_from_nxm_header(*header);
+        if (!*field && !(allow_cookie && is_cookie_pseudoheader(*header))) {
+            VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" is unknown",
+                        NXM_HEADER_ARGS(*header));
+            return OFPERR_OFPBMC_BAD_FIELD;
+        }
     }
 
-    return header;
+    return 0;
+
+error:
+    *header = 0;
+    *field = NULL;
+    return OFPERR_OFPBMC_BAD_LEN;
 }
 
-/* Given NXM/OXM value 'value' and mask 'mask', each 'width' bytes long, checks
- * for any 1-bit in the value where there is a 0-bit in the mask.  Returns 0 if
- * none, otherwise an error code. */
 static enum ofperr
-check_mask_consistency(const uint8_t *p, const struct mf_field *mf)
+nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint32_t *header,
+                const struct mf_field **field,
+                union mf_value *value, union mf_value *mask)
 {
-    unsigned int width = mf->n_bytes;
-    const uint8_t *value = p + 4;
-    const uint8_t *mask = p + 4 + width;
-    unsigned int i;
+    enum ofperr header_error;
+    unsigned int payload_len;
+    const uint8_t *payload;
+    int width;
 
-    for (i = 0; i < width; i++) {
-        if (value[i] & ~mask[i]) {
-            if (!VLOG_DROP_WARN(&rl)) {
-                char *s = nx_match_to_string(p, width * 2 + 4);
-                VLOG_WARN_RL(&rl, "Rejecting NXM/OXM entry %s with 1-bits in "
-                             "value for bits wildcarded by the mask.", s);
-                free(s);
-            }
-            return OFPERR_OFPBMC_BAD_WILDCARDS;
+    header_error = nx_pull_header__(b, allow_cookie, header, field);
+    if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) {
+        return header_error;
+    }
+
+    payload_len = nxm_length(*header);
+    payload = ofpbuf_try_pull(b, payload_len);
+    if (!payload) {
+        VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" calls for %u-byte "
+                    "payload but only %"PRIu32" bytes follow OXM header",
+                    NXM_HEADER_ARGS(*header), payload_len, ofpbuf_size(b));
+        return OFPERR_OFPBMC_BAD_LEN;
+    }
+
+    width = nxm_field_bytes(*header);
+    if (nxm_hasmask(*header)
+        && !is_mask_consistent(*header, payload, payload + width)) {
+        return OFPERR_OFPBMC_BAD_WILDCARDS;
+    }
+
+    memcpy(value, payload, MIN(width, sizeof *value));
+    if (mask) {
+        if (nxm_hasmask(*header)) {
+            memcpy(mask, payload + width, MIN(width, sizeof *mask));
+        } else {
+            memset(mask, 0xff, MIN(width, sizeof *mask));
+        }
+    } else if (nxm_hasmask(*header)) {
+        VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" includes mask but "
+                    "masked OXMs are not allowed here",
+                    NXM_HEADER_ARGS(*header));
+        return OFPERR_OFPBMC_BAD_MASK;
+    }
+
+    return header_error;
+}
+
+/* Attempts to pull an NXM or OXM header, value, and mask (if present) from the
+ * beginning of 'b'.  If successful, stores a pointer to the "struct mf_field"
+ * corresponding to the pulled header in '*field', the value into '*value',
+ * and the mask into '*mask', and returns 0.  On error, returns an OpenFlow
+ * error; in this case, some bytes might have been pulled off 'b' anyhow, and
+ * the output parameters might have been modified.
+ *
+ * If a NULL 'mask' is supplied, masked OXM or NXM entries are treated as
+ * errors (with OFPERR_OFPBMC_BAD_MASK).
+ */
+enum ofperr
+nx_pull_entry(struct ofpbuf *b, const struct mf_field **field,
+              union mf_value *value, union mf_value *mask)
+{
+    uint32_t header;
+
+    return nx_pull_entry__(b, false, &header, field, value, mask);
+}
+
+/* Attempts to pull an NXM or OXM header from the beginning of 'b'.  If
+ * successful, stores a pointer to the "struct mf_field" corresponding to the
+ * pulled header in '*field', stores the header's hasmask bit in '*masked'
+ * (true if hasmask=1, false if hasmask=0), and returns 0.  On error, returns
+ * an OpenFlow error; in this case, some bytes might have been pulled off 'b'
+ * anyhow, and the output parameters might have been modified.
+ *
+ * If NULL 'masked' is supplied, masked OXM or NXM headers are treated as
+ * errors (with OFPERR_OFPBMC_BAD_MASK).
+ */
+enum ofperr
+nx_pull_header(struct ofpbuf *b, const struct mf_field **field, bool *masked)
+{
+    enum ofperr error;
+    uint32_t header;
+
+    error = nx_pull_header__(b, false, &header, field);
+    if (masked) {
+        *masked = !error && nxm_hasmask(header);
+    } else if (!error && nxm_hasmask(header)) {
+        error = OFPERR_OFPBMC_BAD_MASK;
+    }
+    return error;
+}
+
+static enum ofperr
+nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie,
+                    const struct mf_field **field,
+                    union mf_value *value, union mf_value *mask)
+{
+    enum ofperr error;
+    uint32_t header;
+
+    error = nx_pull_entry__(b, allow_cookie, &header, field, value, mask);
+    if (error) {
+        return error;
+    }
+    if (field && *field) {
+        if (!mf_is_mask_valid(*field, mask)) {
+            VLOG_DBG_RL(&rl, "bad mask for field %s", (*field)->name);
+            return OFPERR_OFPBMC_BAD_MASK;
+        }
+        if (!mf_is_value_valid(*field, value)) {
+            VLOG_DBG_RL(&rl, "bad value for field %s", (*field)->name);
+            return OFPERR_OFPBMC_BAD_VALUE;
         }
     }
     return 0;
@@ -119,7 +346,7 @@ static enum ofperr
 nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
             struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
 {
-    uint32_t header;
+    struct ofpbuf b;
 
     ovs_assert((cookie != NULL) == (cookie_mask != NULL));
 
@@ -127,81 +354,46 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
     if (cookie) {
         *cookie = *cookie_mask = htonll(0);
     }
-    if (!match_len) {
-        return 0;
-    }
 
-    for (;
-         (header = nx_entry_ok(p, match_len)) != 0;
-         p += 4 + NXM_LENGTH(header), match_len -= 4 + NXM_LENGTH(header)) {
-        const struct mf_field *mf;
+    ofpbuf_use_const(&b, p, match_len);
+    while (ofpbuf_size(&b)) {
+        const uint8_t *pos = ofpbuf_data(&b);
+        const struct mf_field *field;
+        union mf_value value;
+        union mf_value mask;
         enum ofperr error;
 
-        mf = mf_from_nxm_header(header);
-        if (!mf) {
-            if (strict) {
+        error = nx_pull_match_entry(&b, cookie != NULL, &field, &value, &mask);
+        if (error) {
+            if (error == OFPERR_OFPBMC_BAD_FIELD && !strict) {
+                continue;
+            }
+        } else if (!field) {
+            if (!cookie) {
                 error = OFPERR_OFPBMC_BAD_FIELD;
+            } else if (*cookie_mask) {
+                error = OFPERR_OFPBMC_DUP_FIELD;
             } else {
-                continue;
+                *cookie = value.be64;
+                *cookie_mask = mask.be64;
             }
-        } else if (!mf_are_prereqs_ok(mf, &match->flow)) {
+        } else if (!mf_are_prereqs_ok(field, &match->flow)) {
             error = OFPERR_OFPBMC_BAD_PREREQ;
-        } else if (!mf_is_all_wild(mf, &match->wc)) {
+        } else if (!mf_is_all_wild(field, &match->wc)) {
             error = OFPERR_OFPBMC_DUP_FIELD;
         } else {
-            unsigned int width = mf->n_bytes;
-            union mf_value value;
-
-            memcpy(&value, p + 4, width);
-            if (!mf_is_value_valid(mf, &value)) {
-                error = OFPERR_OFPBMC_BAD_VALUE;
-            } else if (!NXM_HASMASK(header)) {
-                error = 0;
-                mf_set_value(mf, &value, match);
-            } else {
-                union mf_value mask;
-
-                memcpy(&mask, p + 4 + width, width);
-                if (!mf_is_mask_valid(mf, &mask)) {
-                    error = OFPERR_OFPBMC_BAD_MASK;
-                } else {
-                    error = check_mask_consistency(p, mf);
-                    if (!error) {
-                        mf_set(mf, &value, &mask, match);
-                    }
-                }
-            }
-        }
-
-        /* Check if the match is for a cookie rather than a classifier rule. */
-        if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && cookie) {
-            if (*cookie_mask) {
-                error = OFPERR_OFPBMC_DUP_FIELD;
-            } else {
-                unsigned int width = sizeof *cookie;
-
-                memcpy(cookie, p + 4, width);
-                if (NXM_HASMASK(header)) {
-                    memcpy(cookie_mask, p + 4 + width, width);
-                } else {
-                    *cookie_mask = OVS_BE64_MAX;
-                }
-                error = 0;
-            }
+            mf_set(field, &value, &mask, match);
         }
 
         if (error) {
-            VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", "
-                        "field=%"PRIu32", hasmask=%"PRIu32", len=%"PRIu32"), "
-                        "(%s)", header,
-                        NXM_VENDOR(header), NXM_FIELD(header),
-                        NXM_HASMASK(header), NXM_LENGTH(header),
-                        ofperr_to_string(error));
+            VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" "
+                        "within match (%s)", pos -
+                        p, ofperr_to_string(error));
             return error;
         }
     }
 
-    return match_len ? OFPERR_OFPBMC_BAD_LEN : 0;
+    return 0;
 }
 
 static enum ofperr
@@ -334,7 +526,7 @@ nxm_put_8m(struct ofpbuf *b, uint32_t header, uint8_t value, uint8_t mask)
         break;
 
     default:
-        nxm_put_header(b, NXM_MAKE_WILD_HEADER(header));
+        nxm_put_header(b, nxm_make_wild_header(header));
         ofpbuf_put(b, &value, sizeof value);
         ofpbuf_put(b, &mask, sizeof mask);
     }
@@ -367,7 +559,7 @@ nxm_put_16m(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask)
         break;
 
     default:
-        nxm_put_16w(b, NXM_MAKE_WILD_HEADER(header), value, mask);
+        nxm_put_16w(b, nxm_make_wild_header(header), value, mask);
         break;
     }
 }
@@ -399,7 +591,7 @@ nxm_put_32m(struct ofpbuf *b, uint32_t header, ovs_be32 value, ovs_be32 mask)
         break;
 
     default:
-        nxm_put_32w(b, NXM_MAKE_WILD_HEADER(header), value, mask);
+        nxm_put_32w(b, nxm_make_wild_header(header), value, mask);
         break;
     }
 }
@@ -431,7 +623,7 @@ nxm_put_64m(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask)
         break;
 
     default:
-        nxm_put_64w(b, NXM_MAKE_WILD_HEADER(header), value, mask);
+        nxm_put_64w(b, nxm_make_wild_header(header), value, mask);
         break;
     }
 }
@@ -453,7 +645,7 @@ nxm_put_eth_masked(struct ofpbuf *b, uint32_t header,
         if (eth_mask_is_exact(mask)) {
             nxm_put_eth(b, header, value);
         } else {
-            nxm_put_header(b, NXM_MAKE_WILD_HEADER(header));
+            nxm_put_header(b, nxm_make_wild_header(header));
             ofpbuf_put(b, value, ETH_ADDR_LEN);
             ofpbuf_put(b, mask, ETH_ADDR_LEN);
         }
@@ -470,7 +662,7 @@ nxm_put_ipv6(struct ofpbuf *b, uint32_t header,
         nxm_put_header(b, header);
         ofpbuf_put(b, value, sizeof *value);
     } else {
-        nxm_put_header(b, NXM_MAKE_WILD_HEADER(header));
+        nxm_put_header(b, nxm_make_wild_header(header));
         ofpbuf_put(b, value, sizeof *value);
         ofpbuf_put(b, mask, sizeof *mask);
     }
@@ -800,6 +992,29 @@ oxm_put_match(struct ofpbuf *b, const struct match *match,
 
     return match_len;
 }
+
+void
+nx_put_header(struct ofpbuf *b, enum mf_field_id field,
+              enum ofp_version version, bool masked)
+{
+    uint32_t header = mf_oxm_header(field, version);
+    nxm_put_header(b, masked ? nxm_make_wild_header(header) : header);
+}
+
+void
+nx_put_entry(struct ofpbuf *b,
+             enum mf_field_id field, enum ofp_version version,
+             const union mf_value *value, const union mf_value *mask)
+{
+    int n_bytes = mf_from_id(field)->n_bytes;
+    bool masked = mask && !is_all_ones(mask, n_bytes);
+
+    nx_put_header(b, field, version, masked);
+    ofpbuf_put(b, value, n_bytes);
+    if (masked) {
+        ofpbuf_put(b, mask, n_bytes);
+    }
+}
 \f
 /* nx_match_to_string() and helpers. */
 
@@ -808,20 +1023,27 @@ static void format_nxm_field_name(struct ds *, uint32_t header);
 char *
 nx_match_to_string(const uint8_t *p, unsigned int match_len)
 {
-    uint32_t header;
+    struct ofpbuf b;
     struct ds s;
 
     if (!match_len) {
         return xstrdup("<any>");
     }
 
+    ofpbuf_use_const(&b, p, match_len);
     ds_init(&s);
-    while ((header = nx_entry_ok(p, match_len)) != 0) {
-        unsigned int length = NXM_LENGTH(header);
-        unsigned int value_len = nxm_field_bytes(header);
-        const uint8_t *value = p + 4;
-        const uint8_t *mask = value + value_len;
-        unsigned int i;
+    while (ofpbuf_size(&b)) {
+        union mf_value value;
+        union mf_value mask;
+        enum ofperr error;
+        uint32_t header;
+        int value_len;
+
+        error = nx_pull_entry__(&b, true, &header, NULL, &value, &mask);
+        if (error) {
+            break;
+        }
+        value_len = MIN(sizeof value, nxm_field_bytes(header));
 
         if (s.length) {
             ds_put_cstr(&s, ", ");
@@ -830,27 +1052,24 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len)
         format_nxm_field_name(&s, header);
         ds_put_char(&s, '(');
 
-        for (i = 0; i < value_len; i++) {
-            ds_put_format(&s, "%02x", value[i]);
+        for (int i = 0; i < value_len; i++) {
+            ds_put_format(&s, "%02x", ((const uint8_t *) &value)[i]);
         }
-        if (NXM_HASMASK(header)) {
+        if (nxm_hasmask(header)) {
             ds_put_char(&s, '/');
-            for (i = 0; i < value_len; i++) {
-                ds_put_format(&s, "%02x", mask[i]);
+            for (int i = 0; i < value_len; i++) {
+                ds_put_format(&s, "%02x", ((const uint8_t *) &mask)[i]);
             }
         }
         ds_put_char(&s, ')');
-
-        p += 4 + length;
-        match_len -= 4 + length;
     }
 
-    if (match_len) {
+    if (ofpbuf_size(&b)) {
         if (s.length) {
             ds_put_cstr(&s, ", ");
         }
 
-        ds_put_format(&s, "<%u invalid bytes>", match_len);
+        ds_put_format(&s, "<%u invalid bytes>", ofpbuf_size(&b));
     }
 
     return ds_steal_cstr(&s);
@@ -894,13 +1113,20 @@ err:
     return ds_steal_cstr(&s);
 }
 
+void
+nx_format_field_name(enum mf_field_id id, enum ofp_version version,
+                     struct ds *s)
+{
+    format_nxm_field_name(s, mf_oxm_header(id, version));
+}
+
 static void
 format_nxm_field_name(struct ds *s, uint32_t header)
 {
-    const struct mf_field *mf = mf_from_nxm_header(header);
-    if (mf) {
-        ds_put_cstr(s, IS_OXM_HEADER(header) ? mf->oxm_name : mf->nxm_name);
-        if (NXM_HASMASK(header)) {
+    const struct nxm_field *f = nxm_field_by_header(header);
+    if (f) {
+        ds_put_cstr(s, f->name);
+        if (nxm_hasmask(header)) {
             ds_put_cstr(s, "_W");
         }
     } else if (header == NXM_NX_COOKIE) {
@@ -908,52 +1134,35 @@ format_nxm_field_name(struct ds *s, uint32_t header)
     } else if (header == NXM_NX_COOKIE_W) {
         ds_put_cstr(s, "NXM_NX_COOKIE_W");
     } else {
-        ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
+        ds_put_format(s, "%d:%d", nxm_vendor(header), nxm_field(header));
     }
 }
 
+static bool
+streq_len(const char *a, size_t a_len, const char *b)
+{
+    return strlen(b) == a_len && !memcmp(a, b, a_len);
+}
+
 static uint32_t
 parse_nxm_field_name(const char *name, int name_len)
 {
+    const struct nxm_field *f;
     bool wild;
-    int i;
-
-    /* Check whether it's a field name. */
-    wild = name_len > 2 && !memcmp(&name[name_len - 2], "_W", 2);
-    if (wild) {
-        name_len -= 2;
-    }
-
-    for (i = 0; i < MFF_N_IDS; i++) {
-        const struct mf_field *mf = mf_from_id(i);
-        uint32_t header;
-
-        if (mf->nxm_name &&
-            !strncmp(mf->nxm_name, name, name_len) &&
-            mf->nxm_name[name_len] == '\0') {
-            header = mf->nxm_header;
-        } else if (mf->oxm_name &&
-                   !strncmp(mf->oxm_name, name, name_len) &&
-                   mf->oxm_name[name_len] == '\0') {
-            header = mf->oxm_header;
-        } else {
-            continue;
-        }
 
+    f = mf_parse_subfield_name(name, name_len, &wild);
+    if (f) {
         if (!wild) {
-            return header;
-        } else if (mf->maskable != MFM_NONE) {
-            return NXM_MAKE_WILD_HEADER(header);
+            return f->header;
+        } else if (mf_from_id(f->id)->maskable != MFM_NONE) {
+            return nxm_make_wild_header(f->header);
         }
     }
 
-    if (!strncmp("NXM_NX_COOKIE", name, name_len) &&
-        (name_len == strlen("NXM_NX_COOKIE"))) {
-        if (!wild) {
-            return NXM_NX_COOKIE;
-        } else {
-            return NXM_NX_COOKIE_W;
-        }
+    if (streq_len(name, name_len, "NXM_NX_COOKIE")) {
+        return NXM_NX_COOKIE;
+    } else if (streq_len(name, name_len, "NXM_NX_COOKIE_W")) {
+        return NXM_NX_COOKIE_W;
     }
 
     /* Check whether it's a 32-bit field header value as hex.
@@ -1006,7 +1215,7 @@ nx_match_from_string_raw(const char *s, struct ofpbuf *b)
         if (n != nxm_field_bytes(header)) {
             ovs_fatal(0, "%.2s: hex digits expected", s);
         }
-        if (NXM_HASMASK(header)) {
+        if (nxm_hasmask(header)) {
             s += strspn(s, " ");
             if (*s != '/') {
                 ovs_fatal(0, "%s: missing / in masked field %.*s",
@@ -1339,3 +1548,304 @@ nxm_execute_stack_pop(const struct ofpact_stack *pop,
         }
     }
 }
+\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_from_mf_field(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 * 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 * 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) {
+        uint32_t oxm = mf_oxm_header(i, version);
+        uint32_t vendor = nxm_vendor(oxm);
+        int field = nxm_field(oxm);
+
+        if (vendor == 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++) {
+        if (version >= mf_oxm_version(id)) {
+            uint32_t oxm = mf_oxm_header(id, version);
+            uint32_t vendor = nxm_vendor(oxm);
+            int field = nxm_field(oxm);
+
+            if (vendor == 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;
+    struct hmap_node name_node;
+    struct nxm_field nf;
+};
+
+#include "nx-match.inc"
+
+static struct hmap nxm_header_map;
+static struct hmap nxm_name_map;
+static struct nxm_field *nxm_fields[MFF_N_IDS];
+static struct nxm_field *oxm_fields[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 (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_int(nfi->nf.header, 0));
+            hmap_insert(&nxm_name_map, &nfi->name_node,
+                        hash_string(nfi->nf.name, 0));
+            if (is_nxm_header(nfi->nf.header)) {
+                nxm_fields[nfi->nf.id] = &nfi->nf;
+            } else {
+                oxm_fields[nfi->nf.id] = &nfi->nf;
+            }
+        }
+        ovsthread_once_done(&once);
+    }
+}
+
+static const struct nxm_field *
+nxm_field_by_header(uint32_t header)
+{
+    const struct nxm_field_index *nfi;
+
+    nxm_init();
+    if (nxm_hasmask(header)) {
+        header = nxm_make_exact_header(header);
+    }
+
+    HMAP_FOR_EACH_IN_BUCKET (nfi, header_node, hash_int(header, 0),
+                             &nxm_header_map) {
+        if (header == nfi->nf.header) {
+            return &nfi->nf;
+        }
+    }
+    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)
+{
+    nxm_init();
+    return nxm_fields[id];
+}
+
+static const struct nxm_field *
+oxm_field_by_mf_id(enum mf_field_id id)
+{
+    nxm_init();
+    return oxm_fields[id];
+}
+
index 559ff05..b3f9694 100644 (file)
 #include <netinet/in.h>
 #include "compiler.h"
 #include "flow.h"
+#include "meta-flow.h"
 #include "ofp-errors.h"
 #include "openvswitch/types.h"
 
 struct ds;
 struct match;
-struct mf_field;
-struct mf_subfield;
 struct ofpact_reg_move;
 struct ofpact_reg_load;
 struct ofpact_stack;
@@ -42,6 +41,12 @@ struct nx_action_reg_move;
  * See include/openflow/nicira-ext.h for NXM specification.
  */
 
+void mf_format_subfield(const struct mf_subfield *, struct ds *);
+char *mf_parse_subfield__(struct mf_subfield *sf, const char **s)
+    WARN_UNUSED_RESULT;
+char *mf_parse_subfield(struct mf_subfield *, const char *s)
+    WARN_UNUSED_RESULT;
+
 enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
                           struct match *,
                           ovs_be64 *cookie, ovs_be64 *cookie_mask);
@@ -54,11 +59,33 @@ int nx_put_match(struct ofpbuf *, const struct match *,
                  ovs_be64 cookie, ovs_be64 cookie_mask);
 int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version);
 
+/* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field
+ * ID followed by a value and possibly a mask). */
+enum ofperr nx_pull_entry(struct ofpbuf *, const struct mf_field **,
+                          union mf_value *value, union mf_value *mask);
+enum ofperr nx_pull_header(struct ofpbuf *, const struct mf_field **,
+                           bool *masked);
+void nx_put_entry(struct ofpbuf *, enum mf_field_id, enum ofp_version,
+                  const union mf_value *value, const union mf_value *mask);
+void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version,
+                   bool masked);
+
+/* NXM and OXM protocol headers values.
+ *
+ * These are often alternatives to nx_pull_entry/header() and
+ * nx_put_entry/header() for decoding and encoding OXM/NXM.  In those cases,
+ * the nx_*() functions should be preferred because they can support the 64-bit
+ * "experimenter" OXM format (even though it is not yet implemented). */
+uint32_t mf_oxm_header(enum mf_field_id, enum ofp_version oxm_version);
+const struct mf_field *mf_from_nxm_header(uint32_t nxm_header);
+
 char *nx_match_to_string(const uint8_t *, unsigned int match_len);
 char *oxm_match_to_string(const struct ofpbuf *, unsigned int match_len);
 int nx_match_from_string(const char *, struct ofpbuf *);
 int oxm_match_from_string(const char *, struct ofpbuf *);
 
+void nx_format_field_name(enum mf_field_id, enum ofp_version, struct ds *);
+
 char *nxm_parse_reg_move(struct ofpact_reg_move *, const char *)
     WARN_UNUSED_RESULT;
 char *nxm_parse_reg_load(struct ofpact_reg_load *, const char *)
@@ -97,8 +124,12 @@ void nxm_execute_stack_pop(const struct ofpact_stack *,
                             struct flow *, struct flow_wildcards *,
                             struct ofpbuf *);
 
-int nxm_field_bytes(uint32_t header);
-int nxm_field_bits(uint32_t header);
+ovs_be64 oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *, enum ofp_version);
+struct mf_bitmap oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap,
+                                         enum ofp_version);
+struct mf_bitmap oxm_writable_fields(void);
+struct mf_bitmap oxm_matchable_fields(void);
+struct mf_bitmap oxm_maskable_fields(void);
 
 /* Dealing with the 'ofs_nbits' members in several Nicira extensions. */
 
index 39c5a29..ee4f7cf 100644 (file)
@@ -301,6 +301,7 @@ OVS_INSTRUCTIONS
 
 static void ofpacts_update_instruction_actions(struct ofpbuf *openflow,
                                                size_t ofs);
+static void pad_ofpat(struct ofpbuf *openflow, size_t start_ofs);
 
 static enum ofperr ofpacts_verify(const struct ofpact[], size_t ofpacts_len,
                                   uint32_t allowed_ovsinsts);
@@ -730,7 +731,7 @@ encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg,
 
     naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
                                            output_reg->src.n_bits);
-    naor->src = htonl(output_reg->src.field->nxm_header);
+    naor->src = htonl(mf_oxm_header(output_reg->src.field->id, 0));
     naor->max_len = htons(output_reg->max_len);
 }
 
@@ -929,7 +930,7 @@ encode_BUNDLE(const struct ofpact_bundle *bundle,
     if (bundle->dst.field) {
         nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs,
                                               bundle->dst.n_bits);
-        nab->dst = htonl(bundle->dst.field->nxm_header);
+        nab->dst = htonl(mf_oxm_header(bundle->dst.field->id, 0));
     }
 
     slaves = ofpbuf_put_zeros(out, slaves_len);
@@ -1809,8 +1810,8 @@ encode_REG_MOVE(const struct ofpact_reg_move *move,
         narm->n_bits = htons(move->dst.n_bits);
         narm->src_ofs = htons(move->src.ofs);
         narm->dst_ofs = htons(move->dst.ofs);
-        narm->src = htonl(move->src.field->nxm_header);
-        narm->dst = htonl(move->dst.field->nxm_header);
+        narm->src = htonl(mf_oxm_header(move->src.field->id, 0));
+        narm->dst = htonl(mf_oxm_header(move->dst.field->id, 0));
     }
 }
 
@@ -1916,7 +1917,7 @@ encode_REG_LOAD(const struct ofpact_reg_load *load,
 
     narl = put_NXAST_REG_LOAD(out);
     narl->ofs_nbits = nxm_encode_ofs_nbits(load->dst.ofs, load->dst.n_bits);
-    narl->dst = htonl(load->dst.field->nxm_header);
+    narl->dst = htonl(mf_oxm_header(load->dst.field->id, 0));
     narl->value = load->subvalue.be64[1];
 }
 
@@ -1937,11 +1938,12 @@ format_REG_LOAD(const struct ofpact_reg_load *a, struct ds *s)
 struct ofp12_action_set_field {
     ovs_be16 type;                  /* OFPAT12_SET_FIELD. */
     ovs_be16 len;                   /* Length is padded to 64 bits. */
-    ovs_be32 dst;                   /* OXM TLV header */
     /* Followed by:
-     * - Exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4) (between 0 and 7)
-     *   bytes of all-zero bytes
-     */
+     * - An OXM header and value (no mask allowed).
+     * - Enough 0-bytes to pad out to a multiple of 64 bits.
+     *
+     * The "pad" member is the beginning of the above. */
+    uint8_t pad[4];
 };
 OFP_ASSERT(sizeof(struct ofp12_action_set_field) == 8);
 
@@ -1949,47 +1951,48 @@ static enum ofperr
 decode_OFPAT_RAW12_SET_FIELD(const struct ofp12_action_set_field *oasf,
                              struct ofpbuf *ofpacts)
 {
-    uint16_t oasf_len = ntohs(oasf->len);
-    uint32_t oxm_header = ntohl(oasf->dst);
-    uint8_t oxm_length = NXM_LENGTH(oxm_header);
     struct ofpact_set_field *sf;
-    const struct mf_field *mf;
+    enum ofperr error;
+    struct ofpbuf b;
 
-    /* ofp12_action_set_field is padded to 64 bits by zero */
-    if (oasf_len != ROUND_UP(sizeof *oasf + oxm_length, 8)) {
-        return OFPERR_OFPBAC_BAD_SET_LEN;
+    sf = ofpact_put_SET_FIELD(ofpacts);
+
+    ofpbuf_use_const(&b, oasf, ntohs(oasf->len));
+    ofpbuf_pull(&b, 4);
+    error = nx_pull_entry(&b, &sf->field, &sf->value, NULL);
+    if (error) {
+        /* OF1.5 specifically says to use OFPBAC_BAD_SET_MASK in this case. */
+        return (error == OFPERR_OFPBMC_BAD_MASK
+                ? OFPERR_OFPBAC_BAD_SET_MASK
+                : error);
     }
-    if (!is_all_zeros((const uint8_t *)oasf + sizeof *oasf + oxm_length,
-                      oasf_len - oxm_length - sizeof *oasf)) {
+
+    if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
         return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
     }
 
-    if (NXM_HASMASK(oxm_header)) {
-        return OFPERR_OFPBAC_BAD_SET_MASK;
-    }
-    mf = mf_from_nxm_header(oxm_header);
-    if (!mf) {
-        return OFPERR_OFPBAC_BAD_SET_TYPE;
+    /* OpenFlow says specifically that one may not set OXM_OF_IN_PORT via
+     * Set-Field. */
+    if (sf->field->id == MFF_IN_PORT_OXM) {
+        return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
     }
-    ovs_assert(mf->n_bytes == oxm_length);
+
     /* oxm_length is now validated to be compatible with mf_value. */
-    if (!mf->writable) {
-        VLOG_WARN_RL(&rl, "destination field %s is not writable", mf->name);
+    if (!sf->field->writable) {
+        VLOG_WARN_RL(&rl, "destination field %s is not writable",
+                     sf->field->name);
         return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
     }
-    sf = ofpact_put_SET_FIELD(ofpacts);
-    sf->field = mf;
-    memcpy(&sf->value, oasf + 1, mf->n_bytes);
 
     /* The value must be valid for match and must have the OFPVID_PRESENT bit
      * on for OXM_OF_VLAN_VID. */
-    if (!mf_is_value_valid(mf, &sf->value)
-        || (mf->id == MFF_VLAN_VID
+    if (!mf_is_value_valid(sf->field, &sf->value)
+        || (sf->field->id == MFF_VLAN_VID
             && !(sf->value.be16 & htons(OFPVID12_PRESENT)))) {
         struct ds ds = DS_EMPTY_INITIALIZER;
-        mf_format(mf, &sf->value, NULL, &ds);
+        mf_format(sf->field, &sf->value, NULL, &ds);
         VLOG_WARN_RL(&rl, "Invalid value for set field %s: %s",
-                     mf->name, ds_cstr(&ds));
+                     sf->field->name, ds_cstr(&ds));
         ds_destroy(&ds);
 
         return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
@@ -1999,29 +2002,27 @@ decode_OFPAT_RAW12_SET_FIELD(const struct ofp12_action_set_field *oasf,
 
 static void
 ofpact_put_set_field(struct ofpbuf *openflow, enum ofp_version ofp_version,
-                     enum mf_field_id field, uint64_t value)
+                     enum mf_field_id field, uint64_t value_)
 {
-    const struct mf_field *mf = mf_from_id(field);
-    struct ofp12_action_set_field *oasf;
-    ovs_be64 n_value;
+    int n_bytes = mf_from_id(field)->n_bytes;
+    size_t start_ofs = ofpbuf_size(openflow);
+    union mf_value value;
 
-    oasf = put_OFPAT12_SET_FIELD(openflow);
-    oasf->dst = htonl(mf_oxm_header(mf->id, ofp_version));
-    oasf->len = htons(sizeof *oasf + 8);
+    value.be64 = htonll(value_ << (8 * (8 - n_bytes)));
 
-    ovs_assert(mf->n_bytes <= 8);
-    if (mf->n_bytes < 8) {
-        value <<= 8 * (8 - mf->n_bytes);
-    }
-    n_value = htonll(value);
-    ofpbuf_put(openflow, &n_value, 8);
+    put_OFPAT12_SET_FIELD(openflow);
+    ofpbuf_set_size(openflow, ofpbuf_size(openflow) - 4);
+    nx_put_entry(openflow, field, ofp_version, &value, NULL);
+    pad_ofpat(openflow, start_ofs);
 }
 
+
 /* Convert 'sf' to one or two REG_LOADs. */
 static void
 set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow)
 {
     const struct mf_field *mf = sf->field;
+    ovs_be32 header = htonl(mf_oxm_header(mf->id, 0));
     struct nx_action_reg_load *narl;
 
     if (mf->n_bits > 64) {
@@ -2030,17 +2031,17 @@ set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow)
         /* Lower bits first. */
         narl = put_NXAST_REG_LOAD(openflow);
         narl->ofs_nbits = nxm_encode_ofs_nbits(0, 64);
-        narl->dst = htonl(mf->nxm_header);
+        narl->dst = header;
         memcpy(&narl->value, &sf->value.ipv6.s6_addr[8], sizeof narl->value);
         /* Higher bits next. */
         narl = put_NXAST_REG_LOAD(openflow);
         narl->ofs_nbits = nxm_encode_ofs_nbits(64, mf->n_bits - 64);
-        narl->dst = htonl(mf->nxm_header);
+        narl->dst = header;
         memcpy(&narl->value, &sf->value.ipv6.s6_addr[0], sizeof narl->value);
     } else {
         narl = put_NXAST_REG_LOAD(openflow);
         narl->ofs_nbits = nxm_encode_ofs_nbits(0, mf->n_bits);
-        narl->dst = htonl(mf->nxm_header);
+        narl->dst = header;
         memset(&narl->value, 0, 8 - mf->n_bytes);
         memcpy((char*)&narl->value + (8 - mf->n_bytes),
                &sf->value, mf->n_bytes);
@@ -2175,16 +2176,13 @@ encode_SET_FIELD(const struct ofpact_set_field *sf,
     if (ofp_version < OFP12_VERSION) {
         set_field_to_legacy_openflow(sf, ofp_version, out);
     } else {
-        uint16_t padded_value_len = ROUND_UP(sf->field->n_bytes, 8);
-        struct ofp12_action_set_field *oasf;
-        char *value;
-
-        oasf = ofpact_put_raw(out, ofp_version, OFPAT_RAW12_SET_FIELD, 0);
-        oasf->dst = htonl(mf_oxm_header(sf->field->id, ofp_version));
-        oasf->len = htons(sizeof *oasf + padded_value_len);
+        /* Use Set-Field. */
+        size_t start_ofs = ofpbuf_size(out);
 
-        value = ofpbuf_put_zeros(out, padded_value_len);
-        memcpy(value, &sf->value, sf->field->n_bytes);
+        put_OFPAT12_SET_FIELD(out);
+        ofpbuf_set_size(out, ofpbuf_size(out) - 4);
+        nx_put_entry(out, sf->field->id, ofp_version, &sf->value, NULL);
+        pad_ofpat(out, start_ofs);
     }
 }
 
@@ -2309,7 +2307,7 @@ encode_STACK_op(const struct ofpact_stack *stack_action,
 {
     nasp->offset = htons(stack_action->subfield.ofs);
     nasp->n_bits = htons(stack_action->subfield.n_bits);
-    nasp->field = htonl(stack_action->subfield.field->nxm_header);
+    nasp->field = htonl(mf_oxm_header(stack_action->subfield.field->id, 0));
 }
 
 static void
@@ -3528,7 +3526,7 @@ encode_LEARN(const struct ofpact_learn *learn,
         put_u16(out, spec->n_bits | spec->dst_type | spec->src_type);
 
         if (spec->src_type == NX_LEARN_SRC_FIELD) {
-            put_u32(out, spec->src.field->nxm_header);
+            put_u32(out, mf_oxm_header(spec->src.field->id, 0));
             put_u16(out, spec->src.ofs);
         } else {
             size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
@@ -3540,17 +3538,12 @@ encode_LEARN(const struct ofpact_learn *learn,
 
         if (spec->dst_type == NX_LEARN_DST_MATCH ||
             spec->dst_type == NX_LEARN_DST_LOAD) {
-            put_u32(out, spec->dst.field->nxm_header);
+            put_u32(out, mf_oxm_header(spec->dst.field->id, 0));
             put_u16(out, spec->dst.ofs);
         }
     }
 
-    if ((ofpbuf_size(out) - start_ofs) % 8) {
-        ofpbuf_put_zeros(out, 8 - (ofpbuf_size(out) - start_ofs) % 8);
-    }
-
-    nal = ofpbuf_at_assert(out, start_ofs, sizeof *nal);
-    nal->len = htons(ofpbuf_size(out) - start_ofs);
+    pad_ofpat(out, start_ofs);
 }
 
 static char * WARN_UNUSED_RESULT
@@ -3670,7 +3663,7 @@ encode_MULTIPATH(const struct ofpact_multipath *mp,
     nam->max_link = htons(mp->max_link);
     nam->arg = htonl(mp->arg);
     nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits);
-    nam->dst = htonl(mp->dst.field->nxm_header);
+    nam->dst = htonl(mf_oxm_header(mp->dst.field->id, 0));
 }
 
 static char * WARN_UNUSED_RESULT
@@ -6219,3 +6212,15 @@ ofpact_put_raw(struct ofpbuf *buf, enum ofp_version ofp_version,
 
     return oah;
 }
+
+static void
+pad_ofpat(struct ofpbuf *openflow, size_t start_ofs)
+{
+    struct ofp_action_header *oah;
+
+    ofpbuf_put_zeros(openflow, PAD_SIZE(ofpbuf_size(openflow) - start_ofs, 8));
+
+    oah = ofpbuf_at_assert(openflow, start_ofs, sizeof *oah);
+    oah->len = htons(ofpbuf_size(openflow) - start_ofs);
+}
+
index ff84abb..d765d03 100644 (file)
@@ -4560,38 +4560,6 @@ parse_table_features_next_table(struct ofpbuf *payload,
     return 0;
 }
 
-static enum ofperr
-parse_oxm(struct ofpbuf *b, bool loose,
-          const struct mf_field **fieldp, bool *hasmask)
-{
-    ovs_be32 *oxmp;
-    uint32_t oxm;
-
-    oxmp = ofpbuf_try_pull(b, sizeof *oxmp);
-    if (!oxmp) {
-        return OFPERR_OFPBPC_BAD_LEN;
-    }
-    oxm = ntohl(*oxmp);
-
-    /* Determine '*hasmask'.  If 'oxm' is masked, convert it to the equivalent
-     * unmasked version, because the table of OXM fields we support only has
-     * masked versions of fields that we support with masks, but we should be
-     * able to parse the masked versions of those here. */
-    *hasmask = NXM_HASMASK(oxm);
-    if (*hasmask) {
-        if (NXM_LENGTH(oxm) & 1) {
-            return OFPERR_OFPBPC_BAD_VALUE;
-        }
-        oxm = NXM_HEADER(NXM_VENDOR(oxm), NXM_FIELD(oxm), NXM_LENGTH(oxm) / 2);
-    }
-
-    *fieldp = mf_from_nxm_header(oxm);
-    if (!*fieldp) {
-        log_property(loose, "unknown OXM field %#"PRIx32, ntohl(*oxmp));
-    }
-    return *fieldp ? 0 : OFPERR_OFPBMC_BAD_FIELD;
-}
-
 static enum ofperr
 parse_oxms(struct ofpbuf *payload, bool loose,
            struct mf_bitmap *exactp, struct mf_bitmap *maskedp)
@@ -4604,7 +4572,7 @@ parse_oxms(struct ofpbuf *payload, bool loose,
         enum ofperr error;
         bool hasmask;
 
-        error = parse_oxm(payload, loose, &field, &hasmask);
+        error = nx_pull_header(payload, &field, &hasmask);
         if (!error) {
             bitmap_set1(hasmask ? masked.bm : exact.bm, field->id);
         } else if (error != OFPERR_OFPBMC_BAD_FIELD || !loose) {
@@ -4821,15 +4789,8 @@ put_fields_property(struct ofpbuf *reply,
 
     start_ofs = start_property(reply, property);
     BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) {
-        uint32_t h_oxm = mf_oxm_header(field, version);
-        ovs_be32 n_oxm;
-
-        if (masks && bitmap_is_set(masks->bm, field)) {
-            h_oxm = NXM_MAKE_WILD_HEADER(h_oxm);
-        }
-
-        n_oxm = htonl(h_oxm);
-        ofpbuf_put(reply, &n_oxm, sizeof n_oxm);
+        nx_put_header(reply, field, version,
+                      masks && bitmap_is_set(masks->bm, field));
     }
     end_property(reply, start_ofs);
 }
@@ -5357,46 +5318,6 @@ ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *stats,
     out->matched_count = htonll(stats->matched_count);
 }
 
-static ovs_be64
-mf_bitmap_to_oxm_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) {
-        uint32_t oxm = mf_oxm_header(i, version);
-        uint32_t vendor = NXM_VENDOR(oxm);
-        int field = NXM_FIELD(oxm);
-
-        if (vendor == OFPXMC12_OPENFLOW_BASIC && field < 64) {
-            oxm_bitmap |= UINT64_C(1) << field;
-        }
-    }
-    return htonll(oxm_bitmap);
-}
-
-static struct mf_bitmap
-mf_bitmap_from_oxm_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++) {
-        const struct mf_field *f = mf_from_id(id);
-        uint32_t oxm = f->oxm_header;
-        uint32_t vendor = NXM_VENDOR(oxm);
-        int field = NXM_FIELD(oxm);
-
-        if (version >= f->oxm_version
-            && vendor == OFPXMC12_OPENFLOW_BASIC
-            && field < 64
-            && oxm_bitmap & htonll(UINT64_C(1) << field)) {
-            bitmap_set1(fields.bm, id);
-        }
-    }
-    return fields;
-}
-
 static void
 ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
                               const struct ofputil_table_features *features,
@@ -5407,16 +5328,16 @@ ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
     out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = features->table_id;
     ovs_strlcpy(out->name, features->name, sizeof out->name);
-    out->match = mf_bitmap_to_oxm_bitmap(&features->match, OFP12_VERSION);
-    out->wildcards = mf_bitmap_to_oxm_bitmap(&features->wildcard,
+    out->match = oxm_bitmap_from_mf_bitmap(&features->match, OFP12_VERSION);
+    out->wildcards = oxm_bitmap_from_mf_bitmap(&features->wildcard,
                                              OFP12_VERSION);
     out->write_actions = ofpact_bitmap_to_openflow(
         features->nonmiss.write.ofpacts, OFP12_VERSION);
     out->apply_actions = ofpact_bitmap_to_openflow(
         features->nonmiss.apply.ofpacts, OFP12_VERSION);
-    out->write_setfields = mf_bitmap_to_oxm_bitmap(
+    out->write_setfields = oxm_bitmap_from_mf_bitmap(
         &features->nonmiss.write.set_fields, OFP12_VERSION);
-    out->apply_setfields = mf_bitmap_to_oxm_bitmap(
+    out->apply_setfields = oxm_bitmap_from_mf_bitmap(
         &features->nonmiss.apply.set_fields, OFP12_VERSION);
     out->metadata_match = features->metadata_match;
     out->metadata_write = features->metadata_write;
@@ -5569,15 +5490,15 @@ ofputil_decode_ofp12_table_stats(struct ofpbuf *msg,
         ots->write_actions, OFP12_VERSION);
     features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
         ots->apply_actions, OFP12_VERSION);
-    features->nonmiss.write.set_fields = mf_bitmap_from_oxm_bitmap(
+    features->nonmiss.write.set_fields = oxm_bitmap_to_mf_bitmap(
         ots->write_setfields, OFP12_VERSION);
-    features->nonmiss.apply.set_fields = mf_bitmap_from_oxm_bitmap(
+    features->nonmiss.apply.set_fields = oxm_bitmap_to_mf_bitmap(
         ots->apply_setfields, OFP12_VERSION);
     features->miss = features->nonmiss;
 
-    features->match = mf_bitmap_from_oxm_bitmap(ots->match, OFP12_VERSION);
-    features->wildcard = mf_bitmap_from_oxm_bitmap(ots->wildcards,
-                                                   OFP12_VERSION);
+    features->match = oxm_bitmap_to_mf_bitmap(ots->match, OFP12_VERSION);
+    features->wildcard = oxm_bitmap_to_mf_bitmap(ots->wildcards,
+                                                 OFP12_VERSION);
     bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
 
     stats->table_id = ots->table_id;
index 127d8c3..2cb93b0 100644 (file)
@@ -2895,28 +2895,14 @@ query_tables(struct ofproto *ofproto,
              struct ofputil_table_features **featuresp,
              struct ofputil_table_stats **statsp)
 {
-    struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER;
-    struct mf_bitmap match = MF_BITMAP_INITIALIZER;
-    struct mf_bitmap mask = MF_BITMAP_INITIALIZER;
+    struct mf_bitmap rw_fields = oxm_writable_fields();
+    struct mf_bitmap match = oxm_matchable_fields();
+    struct mf_bitmap mask = oxm_maskable_fields();
 
     struct ofputil_table_features *features;
     struct ofputil_table_stats *stats;
     int i;
 
-    for (i = 0; i < MFF_N_IDS; i++) {
-        const struct mf_field *mf = mf_from_id(i);
-
-        if (mf->writable) {
-            bitmap_set1(rw_fields.bm, i);
-        }
-        if (mf->oxm_header || mf->nxm_header) {
-            bitmap_set1(match.bm, i);
-            if (mf->maskable == MFM_FULLY) {
-                bitmap_set1(mask.bm, i);
-            }
-        }
-    }
-
     features = *featuresp = xcalloc(ofproto->n_tables, sizeof *features);
     for (i = 0; i < ofproto->n_tables; i++) {
         struct ofputil_table_features *f = &features[i];
index 9fbae5e..5b5a500 100644 (file)
@@ -502,6 +502,32 @@ AT_CHECK(
   [0], [expout], [experr])
 AT_CLEANUP
 
+dnl Our primary goal here is to verify OpenFlow 1.2-specific changes,
+dnl so the list of tests is short.
+AT_SETUP([OpenFlow 1.2 action translation])
+AT_KEYWORDS([ofp-actions OF1.2])
+AT_DATA([test-data], [dnl
+# actions=LOCAL
+0000 0010 fffffffe 04d2 000000000000
+
+# bad OpenFlow12 actions: OFPBAC_BAD_SET_MASK
+& ofp_actions|WARN|bad action at offset 0 (OFPBAC_BAD_SET_MASK):
+& 00000000  00 19 00 18 80 00 09 0c-00 00 00 00 12 34 00 00
+& 00000010  00 00 ff ff 00 00 00 00-
+0019 0018 8000090c 000000001234 00000000ffff 00000000
+
+])
+sed '/^[[#&]]/d' < test-data > input.txt
+sed -n 's/^# //p; /^$/p' < test-data > expout
+sed -n 's/^& //p' < test-data > experr
+AT_CAPTURE_FILE([input.txt])
+AT_CAPTURE_FILE([expout])
+AT_CAPTURE_FILE([experr])
+AT_CHECK(
+  [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-actions OpenFlow12 < input.txt],
+  [0], [expout], [experr])
+AT_CLEANUP
+
 dnl Our primary goal here is to verify that OpenFlow 1.5-specific changes,
 dnl so the list of tests is short.
 AT_SETUP([OpenFlow 1.5 action translation])
@@ -513,12 +539,11 @@ AT_DATA([test-data], [dnl
 # actions=move:NXM_OF_IN_PORT[]->NXM_OF_VLAN_TCI[]
 001c 0018 0010 0000 0000 0008 00000002 00000802 00000000
 
-dnl This action has a lot more wrong with it than the hasmask bit, but
-dnl the current OVS implementation checks for that first.
 # bad OpenFlow15 actions: OFPBAC_BAD_SET_MASK
 & ofp_actions|WARN|bad action at offset 0 (OFPBAC_BAD_SET_MASK):
-& 00000000  00 19 00 08 00 00 01 00-
-0019 0008 0000 0100
+& 00000000  00 19 00 18 80 00 09 0c-00 00 00 00 12 34 00 00
+& 00000010  00 00 ff ff 00 00 00 00-
+0019 0018 8000090c 000000001234 00000000ffff 00000000
 
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
index 4269311..e5c0e98 100644 (file)
@@ -617,7 +617,7 @@ NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(07) NXM_OF_TCP_DST(4231)
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_NX_TCP_FLAGS(0131)
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_NX_TCP_FLAGS_W(00F0/0FF0)
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_NX_TCP_FLAGS_W(01E2/ffff)
-NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(07) NXM_NX_TCP_FLAGS(4321)
+NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(07) NXM_NX_TCP_FLAGS(0fff)
 
 # UDP source port
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(11) NXM_OF_UDP_SRC(8732)
@@ -654,7 +654,7 @@ NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_SPA_W(C0a81234/FFFFFF00)
 NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_SPA_W(C0a81234/aaaaaa00)
 NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_SPA_W(C0a81234/ffffffff)
 NXM_OF_ETH_TYPE(0800) NXM_OF_ARP_SPA(ac100014)
-NXM_OF_ARP_SPA_W(C0D8fedc/FFFF0000)
+NXM_OF_ARP_SPA_W(C0D80000/FFFF0000)
 
 # ARP destination protocol address
 NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_TPA(ac100014)
@@ -687,7 +687,7 @@ NXM_OF_ETH_TYPE(8035) NXM_OF_ARP_SPA_W(C0a81200/FFFFFF00)
 NXM_OF_ETH_TYPE(8035) NXM_OF_ARP_SPA_W(C0a81234/aaaaaa00)
 NXM_OF_ETH_TYPE(8035) NXM_OF_ARP_SPA_W(C0a81234/ffffffff)
 NXM_OF_ETH_TYPE(0800) NXM_OF_ARP_SPA(ac100014)
-NXM_OF_ARP_SPA_W(C0D8fedc/FFFF0000)
+NXM_OF_ARP_SPA_W(C0D80000/FFFF0000)
 
 # RARP destination protocol address
 NXM_OF_ETH_TYPE(8035) NXM_OF_ARP_TPA(ac100014)
@@ -714,7 +714,7 @@ NXM_OF_ETH_TYPE(86dd) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/fffffff
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/5a5a5a5a5a5a5a5a0000000000000000)
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffffffffffffffffffff)
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/00000000000000000000000000000000)
-NXM_OF_ETH_TYPE(0800) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/00000000000000000000000000000000)
+NXM_OF_ETH_TYPE(0800) NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffffffff000000000000)
 
 # IPv6 destination
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IPV6_DST(20010db83c4d00010002000300040005)
@@ -783,7 +783,7 @@ NXM_OF_ETH_TYPE(86dd) NXM_NX_IP_FRAG(f3)
 NXM_NX_COOKIE(00000000abcdef01)
 NXM_NX_COOKIE_W(84200000abcdef01/84200000FFFFFFFF)
 NXM_NX_COOKIE_W(84200000abcdef01/ffffffffffffffff)
-NXM_NX_COOKIE_W(84200000abcdef01/0000000000000000)
+NXM_NX_COOKIE_W(0000000000000000/0000000000000000)
 
 # Tunnel ID.
 NXM_NX_TUN_ID(00000000abcdef01)
@@ -798,7 +798,7 @@ NXM_NX_REG0_W(a0e0d050/ffffffff)
 NXM_NX_REG0_W(00000000/00000000)
 
 # Invalid field number.
-01020304(1111/2222)
+01020304(1111/3333)
 
 # Unimplemented registers.
 #
@@ -1096,7 +1096,7 @@ nx_pull_match() returned error OFPBMC_BAD_FIELD
 # Check that at least the first warning made it.  (It's rate-limited
 # so a variable number could show up, especially under valgrind etc.)
 AT_CHECK([grep '1-bits in value' stderr | sed 1q], [0], [dnl
-nx_match|WARN|Rejecting NXM/OXM entry NXM_OF_ETH_DST_W(ffffffffffff/010000000000) with 1-bits in value for bits wildcarded by the mask.
+nx_match|WARN|Rejecting NXM/OXM entry 0:1:1:12 with 1-bits in value for bits wildcarded by the mask.
 ])
 
 # Check that there wasn't any other stderr output.
@@ -1647,15 +1647,16 @@ AT_CLEANUP
 AT_SETUP([ovs-ofctl parse-nx-match loose])
 AT_KEYWORDS([nx-match])
 AT_DATA([nx-match.txt], [dnl
-NXM_OF_IN_PORT(0001), 01020304(1111/2222), NXM_OF_ETH_TYPE(0800)
+NXM_OF_IN_PORT(0001), 01020304(1111/3333), NXM_OF_ETH_TYPE(0800)
 ])
 
 AT_CHECK([ovs-ofctl --strict parse-nx-match < nx-match.txt], [0], [dnl
 nx_pull_match() returned error OFPBMC_BAD_FIELD
 ])
 
-AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [dnl
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' -vnx_match parse-nx-match < nx-match.txt], [0], [dnl
 NXM_OF_IN_PORT(0001), NXM_OF_ETH_TYPE(0800)
+], [nx_match|DBG|OXM header 258:1:1:4 is unknown
 ])
 AT_CLEANUP
 
@@ -1715,7 +1716,7 @@ OXM_OF_VLAN_VID_W(1000/1000), OXM_OF_VLAN_PCP(01)  # Packets with any VID, PCP=1
 OXM_OF_ETH_TYPE(0800) OXM_OF_IP_DSCP(f0)
 OXM_OF_ETH_TYPE(0800) OXM_OF_IP_DSCP(41)
 OXM_OF_ETH_TYPE(0800) OXM_OF_IP_DSCP(3f)
-OXM_OF_IP_DSCP(f0)
+OXM_OF_IP_DSCP(3f)
 
 # IP ECN
 OXM_OF_ETH_TYPE(0800) OXM_OF_IP_ECN(03)
@@ -1808,7 +1809,7 @@ OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SPA_W(C0a81200/FFFFFF00)
 OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SPA_W(C0a81234/FFFFFFFF)
 OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SPA_W(00000000/00000000)
 OXM_OF_ETH_TYPE(0800) OXM_OF_ARP_SPA(ac100014)
-OXM_OF_ARP_SPA_W(C0D8fedc/FFFF0000)
+OXM_OF_ARP_SPA_W(C0D80000/FFFF0000)
 
 # ARP destination protocol address
 OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_TPA(ac100014)
@@ -1895,7 +1896,7 @@ OXM_OF_PKT_REG0_W(00000000a0e0d050/00000000f0f0f0f0), OXM_OF_PKT_REG1_W(a0e0d050
 OXM_OF_PKT_REG0_W(00000000a0e0d050/00000000f0f0f0f0), OXM_OF_PKT_REG1_W(a0e0d05000000000/ffffffff00000000)
 
 # Invalid field number.
-01020304(1111/2222)
+01020304(1111/3333)
 ])
 AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' --strict parse-oxm OpenFlow12 < oxm.txt],
   [0], [dnl
@@ -2138,7 +2139,7 @@ nx_pull_match() returned error OFPBMC_BAD_FIELD
 # Check that at least the first warning made it.  (It's rate-limited
 # so a variable number could show up, especially under valgrind etc.)
 AT_CHECK([grep '1-bits in value' stderr | sed 1q], [0], [dnl
-nx_match|WARN|Rejecting NXM/OXM entry OXM_OF_METADATA_W(1234567890abcdef/ffff0000ffff0000) with 1-bits in value for bits wildcarded by the mask.
+nx_match|WARN|Rejecting NXM/OXM entry 32768:2:1:16 with 1-bits in value for bits wildcarded by the mask.
 ])
 
 # Check that there wasn't any other stderr output.
@@ -2197,7 +2198,7 @@ AT_CLEANUP
 AT_SETUP([ovs-ofctl parse-oxm loose])
 AT_KEYWORDS([oxm])
 AT_DATA([oxm.txt], [dnl
-OXM_OF_IN_PORT(00000001), 01020304(1111/2222), OXM_OF_ETH_TYPE(0800)
+OXM_OF_IN_PORT(00000001), 01020304(1111/3333), OXM_OF_ETH_TYPE(0800)
 ])
 
 AT_CHECK([ovs-ofctl --strict parse-oxm OpenFlow12 < oxm.txt], [0], [dnl
index 872f020..2918f04 100644 (file)
@@ -37,6 +37,7 @@
 #include "mcast-snooping.h"
 #include "meta-flow.h"
 #include "netdev.h"
+#include "nx-match.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"