ovs-ofctl: Fix memory leak in "check-vlan" test command.
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index 3f64178..622e32f 100644 (file)
@@ -40,6 +40,7 @@
 #include "odp-util.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-parse.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
@@ -393,21 +394,10 @@ open_vconn(const char *name, struct vconn **vconnp)
     return open_vconn__(name, "mgmt", vconnp);
 }
 
-static void *
-alloc_stats_request(size_t rq_len, uint16_t type, struct ofpbuf **bufferp)
-{
-    struct ofp_stats_msg *rq;
-
-    rq = make_openflow(rq_len, OFPT10_STATS_REQUEST, bufferp);
-    rq->type = htons(type);
-    rq->flags = htons(0);
-    return rq;
-}
-
 static void
 send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
 {
-    update_openflow_length(buffer);
+    ofpmsg_update_length(buffer);
     run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
 }
 
@@ -417,7 +407,7 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request)
     struct vconn *vconn;
     struct ofpbuf *reply;
 
-    update_openflow_length(request);
+    ofpmsg_update_length(request);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     ofp_print(stdout, reply->data, reply->size, verbosity + 1);
@@ -426,20 +416,26 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request)
 }
 
 static void
-dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
+dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
 {
     struct ofpbuf *request;
-    make_openflow(sizeof(struct ofp_header), request_type, &request);
+    request = ofpraw_alloc(raw, OFP10_VERSION, 0);
     dump_transaction(vconn_name, request);
 }
 
 static void
 dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request)
 {
-    ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
-    ovs_be16 stats_type = ((struct ofp_stats_msg *) request->data)->type;
+    const struct ofp_header *request_oh = request->data;
+    ovs_be32 send_xid = request_oh->xid;
+    enum ofpraw request_raw;
+    enum ofpraw reply_raw;
     bool done = false;
 
+    ofpraw_decode_partial(&request_raw, request->data, request->size);
+    reply_raw = ofpraw_stats_request_to_reply(request_raw,
+                                              request_oh->version);
+
     send_openflow_buffer(vconn, request);
     while (!done) {
         ovs_be32 recv_xid;
@@ -448,16 +444,15 @@ dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request)
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
         recv_xid = ((struct ofp_header *) reply->data)->xid;
         if (send_xid == recv_xid) {
-            const struct ofp_stats_msg *osm = reply->data;
-            const struct ofp_header *oh = reply->data;
+            enum ofpraw raw;
 
             ofp_print(stdout, reply->data, reply->size, verbosity + 1);
 
-            if (oh->type == OFPT_ERROR) {
+            ofpraw_decode(&raw, reply->data);
+            if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
                 done = true;
-            } else if (oh->type == OFPT10_STATS_REPLY
-                       && osm->type == stats_type) {
-                done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+            } else if (raw == reply_raw) {
+                done = !ofpmp_more(reply->data);
             } else {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
@@ -482,10 +477,11 @@ dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
 }
 
 static void
-dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
+dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw)
 {
     struct ofpbuf *request;
-    alloc_stats_request(sizeof(struct ofp_stats_msg), stats_type, &request);
+
+    request = ofpraw_alloc(raw, OFP10_VERSION, 0);
     dump_stats_transaction(vconn_name, request);
 }
 
@@ -500,7 +496,7 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests)
     struct ofpbuf *request, *reply;
 
     LIST_FOR_EACH (request, list_node, requests) {
-        update_openflow_length(request);
+        ofpmsg_update_length(request);
     }
 
     run(vconn_transact_multiple_noreply(vconn, requests, &reply),
@@ -531,38 +527,31 @@ static void
 fetch_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
 {
     struct ofp_switch_config *config;
-    struct ofp_header *header;
     struct ofpbuf *request;
     struct ofpbuf *reply;
+    enum ofptype type;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_GET_CONFIG_REQUEST,
-                  &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION, 0);
     run(vconn_transact(vconn, request, &reply),
         "talking to %s", vconn_get_name(vconn));
 
-    header = reply->data;
-    if (header->type != OFPT_GET_CONFIG_REPLY ||
-        header->length != htons(sizeof *config)) {
+    if (ofptype_pull(&type, reply) || type != OFPTYPE_GET_CONFIG_REPLY) {
         ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
     }
 
-    config = reply->data;
+    config = ofpbuf_pull(reply, sizeof *config);
     *config_ = *config;
 
     ofpbuf_delete(reply);
 }
 
 static void
-set_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
+set_switch_config(struct vconn *vconn, const struct ofp_switch_config *config)
 {
-    struct ofp_switch_config *config;
-    struct ofp_header save_header;
     struct ofpbuf *request;
 
-    config = make_openflow(sizeof *config, OFPT_SET_CONFIG, &request);
-    save_header = config->header;
-    *config = *config_;
-    config->header = save_header;
+    request = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, OFP10_VERSION, 0);
+    ofpbuf_put(request, config, sizeof *config);
 
     transact_noreply(vconn, request);
 }
@@ -576,8 +565,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
     struct ofpbuf *reply;
     bool trunc;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST,
-                  &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
 
@@ -591,21 +579,22 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
         /* The Features Reply may not contain all the ports, so send a
          * Port Description stats request, which doesn't have size
          * constraints. */
-        dump_trivial_stats_transaction(vconn_name, OFPST_PORT_DESC);
+        dump_trivial_stats_transaction(vconn_name,
+                                       OFPRAW_OFPST_PORT_DESC_REQUEST);
     }
-    dump_trivial_transaction(vconn_name, OFPT_GET_CONFIG_REQUEST);
+    dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
 }
 
 static void
 ofctl_dump_desc(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_DESC);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_DESC_REQUEST);
 }
 
 static void
 ofctl_dump_tables(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST);
 }
 
 static bool
@@ -614,23 +603,24 @@ fetch_port_by_features(const char *vconn_name,
                        struct ofputil_phy_port *pp, bool *trunc)
 {
     struct ofputil_switch_features features;
-    const struct ofp_switch_features *osf;
+    const struct ofp_header *oh;
     struct ofpbuf *request, *reply;
     struct vconn *vconn;
     enum ofperr error;
+    enum ofptype type;
     struct ofpbuf b;
     bool found = false;
 
     /* Fetch the switch's ofp_switch_features. */
-    make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     vconn_close(vconn);
 
-    osf = reply->data;
-    if (reply->size < sizeof *osf) {
-        ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
-                  vconn_name, reply->size);
+    oh = reply->data;
+    if (ofptype_decode(&type, reply->data)
+        || type != OFPTYPE_FEATURES_REPLY) {
+        ovs_fatal(0, "%s: received bad features reply", vconn_name);
     }
 
     *trunc = false;
@@ -639,13 +629,13 @@ fetch_port_by_features(const char *vconn_name,
         goto exit;
     }
 
-    error = ofputil_decode_switch_features(osf, &features, &b);
+    error = ofputil_decode_switch_features(oh, &features, &b);
     if (error) {
         ovs_fatal(0, "%s: failed to decode features reply (%s)",
                   vconn_name, ofperr_to_string(error));
     }
 
-    while (!ofputil_pull_phy_port(osf->header.version, &b, pp)) {
+    while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
         if (port_no != UINT_MAX
             ? port_no == pp->port_no
             : !strcmp(pp->name, port_name)) {
@@ -667,12 +657,10 @@ fetch_port_by_stats(const char *vconn_name,
     struct ofpbuf *request;
     struct vconn *vconn;
     ovs_be32 send_xid;
-    struct ofpbuf b;
     bool done = false;
     bool found = false;
 
-    alloc_stats_request(sizeof(struct ofp_stats_msg), OFPST_PORT_DESC,
-                        &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0);
     send_xid = ((struct ofp_header *) request->data)->xid;
 
     open_vconn(vconn_name, &vconn);
@@ -684,18 +672,21 @@ fetch_port_by_stats(const char *vconn_name,
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
         recv_xid = ((struct ofp_header *) reply->data)->xid;
         if (send_xid == recv_xid) {
-            const struct ofputil_msg_type *type;
-            struct ofp_stats_msg *osm;
-
-            ofputil_decode_msg_type(reply->data, &type);
-            if (ofputil_msg_type_code(type) != OFPUTIL_OFPST_PORT_DESC_REPLY) {
+            struct ofp_header *oh = reply->data;
+            enum ofptype type;
+            struct ofpbuf b;
+            uint16_t flags;
+
+            ofpbuf_use_const(&b, oh, ntohs(oh->length));
+            if (ofptype_pull(&type, &b)
+                || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
                                         verbosity + 1));
             }
 
-            osm = ofpbuf_at_assert(reply, 0, sizeof *osm);
-            done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+            flags = ofpmp_flags(oh);
+            done = !(flags & OFPSF_REPLY_MORE);
 
             if (found) {
                 /* We've already found the port, but we need to drain
@@ -703,10 +694,7 @@ fetch_port_by_stats(const char *vconn_name,
                 continue;
             }
 
-            ofpbuf_use_const(&b, &osm->header, ntohs(osm->header.length));
-            ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
-
-            while (!ofputil_pull_phy_port(osm->header.version, &b, pp)) {
+            while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
                 if (port_no != UINT_MAX ? port_no == pp->port_no
                                         : !strcmp(pp->name, port_name)) {
                     found = true;
@@ -966,10 +954,11 @@ ofctl_dump_aggregate(int argc, char *argv[])
 static void
 ofctl_queue_stats(int argc, char *argv[])
 {
-    struct ofp_queue_stats_request *req;
+    struct ofp10_queue_stats_request *req;
     struct ofpbuf *request;
 
-    req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST, OFP10_VERSION, 0);
+    req = ofpbuf_put_zeros(request, sizeof *req);
 
     if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
         req->port_no = htons(str_to_port_no(argv[1], argv[2]));
@@ -1228,7 +1217,7 @@ ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED,
         return;
     }
 
-    msg = ofputil_encode_barrier_request();
+    msg = ofputil_encode_barrier_request(vconn_get_version(aux->vconn));
     error = vconn_send_block(aux->vconn, msg);
     if (error) {
         ofpbuf_delete(msg);
@@ -1318,8 +1307,9 @@ monitor_vconn(struct vconn *vconn)
         int retval;
 
         unixctl_server_run(server);
+
         while (!blocked) {
-            uint8_t msg_type;
+            enum ofptype type;
 
             retval = vconn_recv(vconn, &b);
             if (retval == EAGAIN) {
@@ -1335,11 +1325,11 @@ monitor_vconn(struct vconn *vconn)
                 fputs(s, stderr);
             }
 
-            msg_type = ((const struct ofp_header *) b->data)->type;
+            ofptype_decode(&type, b->data);
             ofp_print(stderr, b->data, b->size, verbosity + 2);
             ofpbuf_delete(b);
 
-            if (barrier_aux.conn && msg_type == OFPT10_BARRIER_REPLY) {
+            if (barrier_aux.conn && type == OFPTYPE_BARRIER_REPLY) {
                 unixctl_command_reply(barrier_aux.conn, NULL);
                 barrier_aux.conn = NULL;
             }
@@ -1426,11 +1416,12 @@ ofctl_snoop(int argc OVS_UNUSED, char *argv[])
 static void
 ofctl_dump_ports(int argc, char *argv[])
 {
-    struct ofp_port_stats_request *req;
+    struct ofp10_port_stats_request *req;
     struct ofpbuf *request;
     uint16_t port;
 
-    req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_PORT_REQUEST, OFP10_VERSION, 0);
+    req = ofpbuf_put_zeros(request, sizeof *req);
     port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
     req->port_no = htons(port);
     dump_stats_transaction(argv[1], request);
@@ -1439,7 +1430,7 @@ ofctl_dump_ports(int argc, char *argv[])
 static void
 ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_PORT_DESC);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_PORT_DESC_REQUEST);
 }
 
 static void
@@ -1449,8 +1440,8 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[])
     struct vconn *vconn;
     struct ofpbuf *reply;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
     open_vconn(argv[1], &vconn);
+    request = make_echo_request(vconn_get_version(vconn));
     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
     if (reply->size != sizeof(struct ofp_header)) {
         ovs_fatal(0, "reply does not match request");
@@ -1462,6 +1453,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[])
 static void
 ofctl_packet_out(int argc, char *argv[])
 {
+    enum ofputil_protocol protocol;
     struct ofputil_packet_out po;
     struct ofpbuf ofpacts;
     struct vconn *vconn;
@@ -1477,7 +1469,7 @@ ofctl_packet_out(int argc, char *argv[])
     po.ofpacts = ofpacts.data;
     po.ofpacts_len = ofpacts.size;
 
-    open_vconn(argv[1], &vconn);
+    protocol = open_vconn(argv[1], &vconn);
     for (i = 4; i < argc; i++) {
         struct ofpbuf *packet, *opo;
         const char *error_msg;
@@ -1489,7 +1481,7 @@ ofctl_packet_out(int argc, char *argv[])
 
         po.packet = packet->data;
         po.packet_len = packet->size;
-        opo = ofputil_encode_packet_out(&po);
+        opo = ofputil_encode_packet_out(&po, protocol);
         transact_noreply(vconn, opo);
         ofpbuf_delete(packet);
     }
@@ -1619,28 +1611,29 @@ ofctl_ping(int argc, char *argv[])
     for (i = 0; i < 10; i++) {
         struct timeval start, end;
         struct ofpbuf *request, *reply;
-        struct ofp_header *rq_hdr, *rpy_hdr;
+        const struct ofp_header *rpy_hdr;
+        enum ofptype type;
 
-        rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
-                               OFPT_ECHO_REQUEST, &request);
-        random_bytes(rq_hdr + 1, payload);
+        request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                               payload);
+        random_bytes(ofpbuf_put_uninit(request, payload), payload);
 
         xgettimeofday(&start);
         run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
         xgettimeofday(&end);
 
         rpy_hdr = reply->data;
-        if (reply->size != request->size
-            || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
-            || rpy_hdr->xid != rq_hdr->xid
-            || rpy_hdr->type != OFPT_ECHO_REPLY) {
+        if (ofptype_pull(&type, reply)
+            || type != OFPTYPE_ECHO_REPLY
+            || reply->size != payload
+            || memcmp(request->l3, reply->l3, payload)) {
             printf("Reply does not match request.  Request:\n");
             ofp_print(stdout, request, request->size, verbosity + 2);
             printf("Reply:\n");
             ofp_print(stdout, reply, reply->size, verbosity + 2);
         }
         printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
-               reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid),
+               reply->size, argv[1], ntohl(rpy_hdr->xid),
                    (1000*(double)(end.tv_sec - start.tv_sec))
                    + (.001*(end.tv_usec - start.tv_usec)));
         ofpbuf_delete(request);
@@ -1675,10 +1668,10 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[])
     xgettimeofday(&start);
     for (i = 0; i < count; i++) {
         struct ofpbuf *request, *reply;
-        struct ofp_header *rq_hdr;
 
-        rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
-        memset(rq_hdr + 1, 0, payload_size);
+        request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                               payload_size);
+        ofpbuf_put_zeros(request, payload_size);
         run(vconn_transact(vconn, request, &reply), "transact");
         ofpbuf_delete(reply);
     }
@@ -1851,7 +1844,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
         version->cookie = fm.new_cookie;
         version->idle_timeout = fm.idle_timeout;
         version->hard_timeout = fm.hard_timeout;
-        version->flags = fm.flags & (OFPFF_SEND_FLOW_REM | OFPFF_EMERG);
+        version->flags = fm.flags & (OFPFF_SEND_FLOW_REM | OFPFF10_EMERG);
         version->ofpacts = fm.ofpacts;
         version->ofpacts_len = fm.ofpacts_len;
 
@@ -1876,23 +1869,21 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
     struct ofpbuf *reply = *replyp;
 
     for (;;) {
-        ovs_be16 flags;
         int retval;
+        bool more;
 
         /* Get a flow stats reply message, if we don't already have one. */
         if (!reply) {
-            const struct ofputil_msg_type *type;
-            enum ofputil_msg_code code;
+            enum ofptype type;
+            enum ofperr error;
 
             do {
                 run(vconn_recv_block(vconn, &reply),
                     "OpenFlow packet receive failed");
             } while (((struct ofp_header *) reply->data)->xid != send_xid);
 
-            ofputil_decode_msg_type(reply->data, &type);
-            code = ofputil_msg_type_code(type);
-            if (code != OFPUTIL_OFPST_FLOW_REPLY &&
-                code != OFPUTIL_NXST_FLOW_REPLY) {
+            error = ofptype_decode(&type, reply->data);
+            if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
                                         verbosity + 1));
@@ -1907,10 +1898,10 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
             return true;
 
         case EOF:
-            flags = ((const struct ofp_stats_msg *) reply->l2)->flags;
+            more = ofpmp_more(reply->l2);
             ofpbuf_delete(reply);
             reply = NULL;
-            if (!(flags & htons(OFPSF_REPLY_MORE))) {
+            if (!more) {
                 *replyp = NULL;
                 return false;
             }
@@ -2192,28 +2183,45 @@ ofctl_parse_nxm__(bool oxm)
 
         /* Convert string to nx_match. */
         ofpbuf_init(&nx_match, 0);
-        match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
+        if (oxm) {
+            match_len = oxm_match_from_string(ds_cstr(&in), &nx_match);
+        } else {
+            match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
+        }
 
         /* Convert nx_match to cls_rule. */
         if (strict) {
-            error = nx_pull_match(&nx_match, match_len, 0, &rule,
-                                  &cookie, &cookie_mask);
+            if (oxm) {
+                error = oxm_pull_match(&nx_match, 0, &rule);
+            } else {
+                error = nx_pull_match(&nx_match, match_len, 0, &rule,
+                                      &cookie, &cookie_mask);
+            }
         } else {
-            error = nx_pull_match_loose(&nx_match, match_len, 0, &rule,
-                                        &cookie, &cookie_mask);
+            if (oxm) {
+                error = oxm_pull_match_loose(&nx_match, 0, &rule);
+            } else {
+                error = nx_pull_match_loose(&nx_match, match_len, 0, &rule,
+                                            &cookie, &cookie_mask);
+            }
         }
 
+
         if (!error) {
             char *out;
 
             /* Convert cls_rule back to nx_match. */
             ofpbuf_uninit(&nx_match);
             ofpbuf_init(&nx_match, 0);
-            match_len = nx_put_match(&nx_match, oxm, &rule,
-                                     cookie, cookie_mask);
+            if (oxm) {
+                match_len = oxm_put_match(&nx_match, &rule);
+                out = oxm_match_to_string(nx_match.data, match_len);
+            } else {
+                match_len = nx_put_match(&nx_match, &rule,
+                                         cookie, cookie_mask);
+                out = nx_match_to_string(nx_match.data, match_len);
+            }
 
-            /* Convert nx_match to string. */
-            out = nx_match_to_string(nx_match.data, match_len);
             puts(out);
             free(out);
         } else {
@@ -2327,20 +2335,50 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 /* "parse-ofp10-match": reads a series of ofp10_match specifications as hex
  * bytes from stdin, converts them to cls_rules, prints them as strings on
  * stdout, and then converts them back to hex bytes and prints any differences
- * from the input. */
+ * from the input.
+ *
+ * The input hex bytes may contain "x"s to represent "don't-cares", bytes whose
+ * values are ignored in the input and will be set to zero when OVS converts
+ * them back to hex bytes.  ovs-ofctl actually sets "x"s to random bits when
+ * it does the conversion to hex, to ensure that in fact they are ignored. */
 static void
 ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
+    struct ds expout;
     struct ds in;
 
     ds_init(&in);
+    ds_init(&expout);
     while (!ds_get_preprocessed_line(&in, stdin)) {
-        struct ofpbuf match_in;
+        struct ofpbuf match_in, match_expout;
         struct ofp10_match match_out;
         struct ofp10_match match_normal;
         struct cls_rule rule;
+        char *p;
+
+        /* Parse hex bytes to use for expected output. */
+        ds_clear(&expout);
+        ds_put_cstr(&expout, ds_cstr(&in));
+        for (p = ds_cstr(&expout); *p; p++) {
+            if (*p == 'x') {
+                *p = '0';
+            }
+        }
+        ofpbuf_init(&match_expout, 0);
+        if (ofpbuf_put_hex(&match_expout, ds_cstr(&expout), NULL)[0] != '\0') {
+            ovs_fatal(0, "Trailing garbage in hex data");
+        }
+        if (match_expout.size != sizeof(struct ofp10_match)) {
+            ovs_fatal(0, "Input is %zu bytes, expected %zu",
+                      match_expout.size, sizeof(struct ofp10_match));
+        }
 
-        /* Parse hex bytes. */
+        /* Parse hex bytes for input. */
+        for (p = ds_cstr(&in); *p; p++) {
+            if (*p == 'x') {
+                *p = "0123456789abcdef"[random_uint32() & 0xf];
+            }
+        }
         ofpbuf_init(&match_in, 0);
         if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
             ovs_fatal(0, "Trailing garbage in hex data");
@@ -2357,7 +2395,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         /* Convert back to ofp10_match and print differences from input. */
         ofputil_cls_rule_to_ofp10_match(&rule, &match_out);
-        print_differences("", match_in.data, match_in.size,
+        print_differences("", match_expout.data, match_expout.size,
                           &match_out, sizeof match_out);
 
         /* Normalize, then convert and compare again. */
@@ -2368,8 +2406,10 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         putchar('\n');
 
         ofpbuf_uninit(&match_in);
+        ofpbuf_uninit(&match_expout);
     }
     ds_destroy(&in);
+    ds_destroy(&expout);
 }
 
 /* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
@@ -2575,10 +2615,11 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
     printf("%04"PRIx16"/%04"PRIx16"\n",
            ntohs(fm.cr.flow.vlan_tci),
            ntohs(fm.cr.wc.vlan_tci_mask));
+    free(string_s);
 
     /* Convert to and from NXM. */
     ofpbuf_init(&nxm, 0);
-    nxm_match_len = nx_put_match(&nxm, false, &rule, htonll(0), htonll(0));
+    nxm_match_len = nx_put_match(&nxm, &rule, htonll(0), htonll(0));
     nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
     error = nx_pull_match(&nxm, nxm_match_len, 0, &nxm_rule, NULL, NULL);
     printf("NXM: %s -> ", nxm_s);
@@ -2594,9 +2635,9 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
 
     /* Convert to and from OXM. */
     ofpbuf_init(&nxm, 0);
-    nxm_match_len = nx_put_match(&nxm, true, &rule, htonll(0), htonll(0));
-    nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
-    error = nx_pull_match(&nxm, nxm_match_len, 0, &nxm_rule, NULL, NULL);
+    nxm_match_len = oxm_put_match(&nxm, &rule);
+    nxm_s = oxm_match_to_string(nxm.data, nxm_match_len);
+    error = oxm_pull_match(&nxm, 0, &nxm_rule);
     printf("OXM: %s -> ", nxm_s);
     if (error) {
         printf("%s\n", ofperr_to_string(error));
@@ -2653,17 +2694,14 @@ ofctl_print_error(int argc OVS_UNUSED, char *argv[])
     }
 
     for (version = 0; version <= UINT8_MAX; version++) {
-        const struct ofperr_domain *domain;
-
-        domain = ofperr_domain_from_version(version);
-        if (!domain) {
+        const char *name = ofperr_domain_get_name(version);
+        if (!name) {
             continue;
         }
-
         printf("%s: %d,%d\n",
-               ofperr_domain_get_name(domain),
-               ofperr_get_type(error, domain),
-               ofperr_get_code(error, domain));
+               ofperr_domain_get_name(version),
+               ofperr_get_type(error, version),
+               ofperr_get_code(error, version));
     }
 }