[ovs-dev] [PATCH] v3: Initial OpenFlow 1.3 support

Jarno Rajahalme jarno.rajahalme at nsn.com
Tue Nov 27 07:17:59 UTC 2012


  Initial OpenFlow 1.3 support with new include/openflow/openflow-1.3.h.
  Most of the messages that differ from 1.2 are implemented. OFPT_SET_ASYNC
  is implemented via NX_SET_ASYNC_CONFIG, other new message types are
  yet to be implemented. Stats replies that add duration fields are implemented at
  encode/decode level only. Test cases for implemented features are included.
  Remaining FIXME:s should not cause runtime aborts. Make check comes out
  clean.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>

 build-aux/extract-ofp-errors       |   21 ++--
 build-aux/extract-ofp-msgs         |    1 +
 include/openflow/automake.mk       |    1 +
 include/openflow/openflow-1.0.h    |    2 +
 include/openflow/openflow-1.1.h    |    4 +-
 include/openflow/openflow-1.2.h    |   25 ++++
 include/openflow/openflow-1.3.h    |  460 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/openflow/openflow-common.h |   10 +-
 include/openflow/openflow.h        |    1 +
 lib/learning-switch.c              |   19 ++-
 lib/nx-match.c                     |    1 +
 lib/ofp-errors.c                   |    3 +
 lib/ofp-errors.h                   |   74 +++++++++++
 lib/ofp-msgs.c                     |    4 +
 lib/ofp-msgs.h                     |  135 ++++++++++++++++++--
 lib/ofp-parse.c                    |    6 +
 lib/ofp-print.c                    |  126 ++++++++++++++++---
 lib/ofp-util.c                     |  290 +++++++++++++++++++++++++++++++++++--------
 lib/ofp-util.h                     |   22 ++--
 lib/rconn.c                        |   18 +++
 ofproto/ofproto.c                  |   56 ++++++---
 tests/learn.at                     |    2 +-
 tests/ofp-errors.at                |    2 +
 tests/ofp-print.at                 |  209 +++++++++++++++++++++++++++++--
 tests/ofp-util.at                  |    7 +-
 25 files changed, 1374 insertions(+), 125 deletions(-)
 create mode 100644 include/openflow/openflow-1.3.h

diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
index db28af8..c327304 100755
--- a/build-aux/extract-ofp-errors
+++ b/build-aux/extract-ofp-errors
@@ -151,7 +151,8 @@ def extract_ofp_errors(filenames):
     names = []
     domain = {}
     reverse = {}
-    for domain_name in ("OF1.0", "OF1.1", "OF1.2", "NX1.0", "NX1.1"):
+    for domain_name in ("OF1.0", "OF1.1", "OF1.2", "OF1.3",
+                        "NX1.0", "NX1.1", "NX1.2", "NX1.3"):
         domain[domain_name] = {}
         reverse[domain_name] = {}
 
@@ -225,17 +226,22 @@ def extract_ofp_errors(filenames):
                 else:
                     code = None
 
-                target_map = {"OF1.0+": ("OF1.0", "OF1.1", "OF1.2"),
-                              "OF1.1+": ("OF1.1", "OF1.2"),
-                              "OF1.2+": ("OF1.2",),
+                target_map = {"OF1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"),
+                              "OF1.1+": ("OF1.1", "OF1.2", "OF1.3"),
+                              "OF1.2+": ("OF1.2", "OF1.3"),
+                              "OF1.3+": ("OF1.3",),
                               "OF1.0":  ("OF1.0",),
                               "OF1.1":  ("OF1.1",),
                               "OF1.2":  ("OF1.2",),
-                              "NX1.0+": ("OF1.0", "OF1.1", "OF1.2"),
+                              "OF1.3":  ("OF1.3",),
+                              "NX1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"),
+                              "NX1.1+": ("OF1.1", "OF1.2", "OF1.3"),
+                              "NX1.2+": ("OF1.2", "OF1.3"),
+                              "NX1.3+": ("OF1.3",),
                               "NX1.0":  ("OF1.0",),
                               "NX1.1":  ("OF1.1",),
-                              "NX1.1+": ("OF1.1",),
-                              "NX1.2":  ("OF1.2",)}
+                              "NX1.2":  ("OF1.2",),
+                              "NX1.3":  ("OF1.3",)}
                 if targets not in target_map:
                     fatal("%s: unknown error domain" % targets)
                 if targets.startswith('NX') and code < 0x100:
@@ -369,6 +375,7 @@ static const struct ofperr_domain %s = {
     output_domain(reverse["OF1.0"], "ofperr_of10", "OpenFlow 1.0", 0x01)
     output_domain(reverse["OF1.1"], "ofperr_of11", "OpenFlow 1.1", 0x02)
     output_domain(reverse["OF1.2"], "ofperr_of12", "OpenFlow 1.2", 0x03)
+    output_domain(reverse["OF1.3"], "ofperr_of13", "OpenFlow 1.3", 0x04)
 
 if __name__ == '__main__':
     if '--help' in sys.argv:
diff --git a/build-aux/extract-ofp-msgs b/build-aux/extract-ofp-msgs
index 9807289..5eaa141 100755
--- a/build-aux/extract-ofp-msgs
+++ b/build-aux/extract-ofp-msgs
@@ -30,6 +30,7 @@ version_map = {"1.0":     (OFP10_VERSION, OFP10_VERSION),
                "1.3+":    (OFP13_VERSION, OFP13_VERSION),
                "1.0-1.1": (OFP10_VERSION, OFP11_VERSION),
                "1.0-1.2": (OFP10_VERSION, OFP12_VERSION),
+               "1.1-1.2": (OFP11_VERSION, OFP12_VERSION),
                "<all>":   (0x01, 0xff)}
 
 def get_line():
diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk
index 38e8eef..f891086 100644
--- a/include/openflow/automake.mk
+++ b/include/openflow/automake.mk
@@ -3,6 +3,7 @@ noinst_HEADERS += \
 	include/openflow/openflow-1.0.h \
 	include/openflow/openflow-1.1.h \
 	include/openflow/openflow-1.2.h \
+	include/openflow/openflow-1.3.h \
 	include/openflow/openflow-common.h \
 	include/openflow/openflow.h
 
diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h
index 9af7740..ae1e1b8 100644
--- a/include/openflow/openflow-1.0.h
+++ b/include/openflow/openflow-1.0.h
@@ -61,6 +61,8 @@ enum ofp_config_flags {
     OFPC_FRAG_NX_MATCH = 3,  /* Make first fragments available for matching. */
     OFPC_FRAG_MASK     = 3,
 
+    /* OFPC_INVALID_TTL_TO_CONTROLLER is deprecated in OpenFlow 1.3 */
+
     /* TTL processing - applicable for IP and MPLS packets. */
     OFPC_INVALID_TTL_TO_CONTROLLER = 1 << 2, /* Send packets with invalid TTL
                                                 to the controller. */
diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h
index c4a5aba..9b2f754 100644
--- a/include/openflow/openflow-1.1.h
+++ b/include/openflow/openflow-1.1.h
@@ -127,6 +127,7 @@ struct ofp11_port {
     ovs_be32 curr_speed;    /* Current port bitrate in kbps. */
     ovs_be32 max_speed;     /* Max port bitrate in kbps */
 };
+OFP_ASSERT(sizeof(struct ofp11_port) == 64);
 
 /* Modify behavior of the physical port */
 struct ofp11_port_mod {
@@ -588,7 +589,8 @@ struct ofp11_flow_stats {
                                   when this is not an exact-match entry. */
     ovs_be16 idle_timeout;     /* Number of seconds idle before expiration. */
     ovs_be16 hard_timeout;     /* Number of seconds before expiration. */
-    uint8_t pad2[6];           /* Align to 64-bits. */
+    ovs_be16 flags;            /* OF 1.3: Set of OFPFF*. */
+    uint8_t  pad2[4];          /* Align to 64-bits. */
     ovs_be64 cookie;           /* Opaque controller-issued identifier. */
     ovs_be64 packet_count;     /* Number of packets in flow. */
     ovs_be64 byte_count;       /* Number of bytes in flow. */
diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h
index 1c3f017..5546313 100644
--- a/include/openflow/openflow-1.2.h
+++ b/include/openflow/openflow-1.2.h
@@ -106,6 +106,11 @@ enum oxm12_ofb_match_fields {
     OFPXMT12_OFB_IPV6_ND_TLL,    /* Target link-layer for ND. */
     OFPXMT12_OFB_MPLS_LABEL,     /* MPLS label. */
     OFPXMT12_OFB_MPLS_TC,        /* MPLS TC. */
+    /* Following added in OpenFlow 1.3 */
+    OFPXMT12_OFB_MPLS_BOS,       /* MPLS BoS bit. */
+    OFPXMT12_OFB_PBB_ISID,       /* PBB I-SID. */
+    OFPXMT12_OFB_TUNNEL_ID,      /* Logical Port Metadata */
+    OFPXMT12_OFB_IPV6_EXTHDR,    /* IPv6 Extension Header pseudo-field */
 
     /* End Marker */
     OFPXMT12_OFB_MAX,
@@ -172,6 +177,13 @@ enum oxm12_ofb_match_fields {
 #define OXM_OF_IPV6_ND_TLL    OXM_HEADER   (OFPXMT12_OFB_IPV6_ND_TLL, 6)
 #define OXM_OF_MPLS_LABEL     OXM_HEADER   (OFPXMT12_OFB_MPLS_LABEL, 4)
 #define OXM_OF_MPLS_TC        OXM_HEADER   (OFPXMT12_OFB_MPLS_TC, 1)
+#define OXM_OF_MPLS_BOS       OXM_HEADER   (OFPXMT12_OFB_MPLS_BOS, 1)
+#define OXM_OF_PBB_ISID       OXM_HEADER   (OFPXMT12_OFB_PBB_ISID, 4)
+#define OXM_OF_PBB_ISID_W     OXM_HEADER_W (OFPXMT12_OFB_PBB_ISID, 4)
+#define OXM_OF_TUNNEL_ID      OXM_HEADER   (OFPXMT12_OFB_TUNNEL_ID, 8)
+#define OXM_OF_TUNNEL_ID_W    OXM_HEADER_W (OFPXMT12_OFB_TUNNEL_ID, 8)
+#define OXM_OF_IPV6_EXTHDR    OXM_HEADER   (OFPXMT12_OFB_IPV6_EXTHDR, 2)
+#define OXM_OF_IPV6_EXTHDR_W  OXM_HEADER_W (OFPXMT12_OFB_IPV6_EXTHDR, 2)
 
 /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
  * special conditions.
@@ -181,6 +193,19 @@ enum ofp12_vlan_id {
     OFPVID12_NONE    = 0x0000, /* No VLAN id was set. */
 };
 
+/* Bit definitions for IPv6 Extension Header pseudo-field. */
+enum ofp12_ipv6exthdr_flags {
+    OFPIEH12_NONEXT = 1 << 0,   /* "No next header" encountered. */
+    OFPIEH12_ESP    = 1 << 1,   /* Encrypted Sec Payload header present. */
+    OFPIEH12_AUTH   = 1 << 2,   /* Authentication header present. */
+    OFPIEH12_DEST   = 1 << 3,   /* 1 or 2 dest headers present. */
+    OFPIEH12_FRAG   = 1 << 4,   /* Fragment header present. */
+    OFPIEH12_ROUTER = 1 << 5,   /* Router header present. */
+    OFPIEH12_HOP    = 1 << 6,   /* Hop-by-hop header present. */
+    OFPIEH12_UNREP  = 1 << 7,   /* Unexpected repeats encountered. */
+    OFPIEH12_UNSEQ  = 1 << 8    /* Unexpected sequencing encountered. */
+};
+
 /* Header for OXM experimenter match fields. */
 struct ofp12_oxm_experimenter_header {
     ovs_be32 oxm_header;   /* oxm_class = OFPXMC_EXPERIMENTER */
diff --git a/include/openflow/openflow-1.3.h b/include/openflow/openflow-1.3.h
new file mode 100644
index 0000000..b321b8d
--- /dev/null
+++ b/include/openflow/openflow-1.3.h
@@ -0,0 +1,460 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+* Junior University
+* Copyright (c) 2011, 2012 Open Networking Foundation
+*
+* We are making the OpenFlow specification and associated documentation
+* (Software) available for public use and benefit with the expectation
+* that others will use, modify and enhance the Software and contribute
+* those enhancements back to the community. However, since we would
+* like to make the Software available for broadest use, with as few
+* restrictions as possible permission is hereby granted, free of
+* charge, to any person obtaining a copy of this Software to deal in
+* the Software under the copyrights without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*
+* The name and trademarks of copyright holder(s) may NOT be used in
+* advertising or publicity pertaining to the Software or any
+* derivatives without specific, written prior permission.
+*/
+
+/* OpenFlow: protocol between controller and datapath. */
+
+#ifndef OPENFLOW_13_H
+#define OPENFLOW_13_H 1
+
+#include "openflow/openflow-1.2.h"
+
+/*
+ * OpenFlow 1.3 modifies the syntax of the following message types:
+ *
+ * OFPT_FEATURES_REPLY     = 6    (opf13_switch_features)
+ *                                 - new field: auxiliary_id
+ *                                 - removed: ofp_ports at the end
+ *
+ * OFPT_PACKET_IN          = 10   (ofp13_packet_in) new field: cookie
+ *
+ * OpenFlow 1.3 adds following new message types:
+ *
+ * * Asynchronous message configuration. *
+ * OFPT13_GET_ASYNC_REQUEST  = 26   (void)
+ * OFPT13_GET_ASYNC_REPLY    = 27   (ofp13_async_config)
+ * OFPT13_SET_ASYNC          = 28   (ofp13_async_config)
+ *
+ * * Meters and rate limiters configuration messages. *
+ * OFPT13_METER_MOD          = 29   (ofp13_meter_mod)
+ *
+ * OpenFlow 1.3 modifies the syntax of the following statistics message types
+ * (now called multipart message types):
+ *
+ * OFPMP13_FLOW_REPLY = 1 (struct ofp13_flow_stats[])
+ * OFPMP13_TABLE_REPLY = 3 (struct ofp13_table_stats[])
+ * OFPMP13_PORT_REPLY = 4 (struct ofp13_port_stats[])
+ * OFPMP13_QUEUE_REPLY = 5, (struct ofp13_queue_stats[])
+ * OFPMP13_GROUP_REPLY = 6, (struct ofp13_group_stats[])
+ *
+ * OpenFlow 1.3 adds the following multipart message types
+ *
+ * Meter statistics:
+ * OFPMP13_METER_REQUEST = 9, (struct ofp13_meter_multipart_request)
+ * OFPMP13_METER_REPLY = 9, (struct ofp13_meter_stats[])
+ *
+ * Meter configuration:
+ * OFPMP13_METER_CONFIG_REQUEST = 10, (struct ofp13_meter_multipart_request)
+ * OFPMP13_METER_CONFIG_REPLY = 10, (struct ofp13_meter_config[])
+ *
+ * Meter features:
+ * OFPMP13_METER_FEATURES_REQUEST = 11 (void)
+ * OFPMP13_METER_FEATURES_REPLY = 11 (struct ofp13_meter_features)
+ *
+ * Table features:
+ * OFPMP13_TABLE_FEATURES_REQUEST = 12, (struct ofp13_table_features[])
+ * OFPMP13_TABLE_FEATURES_REPLY = 12, (struct ofp13_table_features[])
+ *
+ */
+
+enum ofp13_instruction_type {
+    OFPIT13_METER = 6           /* Apply meter (rate limiter) */
+};
+
+#define OFPIT13_ALL (OFPIT11_GOTO_TABLE | OFPIT11_WRITE_METADATA |      \
+                     OFPIT11_WRITE_ACTIONS | OFPIT11_APPLY_ACTIONS |    \
+                     OFPIT11_CLEAR_ACTIONS | OFPIT13_METER)
+
+/* Instruction structure for OFPIT_METER */
+struct ofp13_instruction_meter {
+    ovs_be16 type;              /* OFPIT13_METER */
+    ovs_be16 len;               /* Length is 8. */
+    ovs_be32 meter_id;          /* Meter instance. */
+};
+OFP_ASSERT(sizeof(struct ofp13_instruction_meter) == 8);
+
+enum ofp13_action_type {
+    OFPAT13_PUSH_PBB = 26,     /* Push a new PBB service tag (I-TAG) */
+    OFPAT13_PPO_PBB  = 27      /* Pop the outer PBB service tag (I-TAG) */
+};
+
+/* enum ofp_config_flags value OFPC_INVALID_TTL_TO_CONTROLLER
+ * is deprecated in OpenFlow 1.3 */
+
+/* Flags to configure the table. Reserved for future use. */
+enum ofp13_table_config {
+    OFPTC13_DEPRECATED_MASK = 3  /* Deprecated bits */
+};
+
+/* OpenFlow 1.3 specific flags
+ * (struct ofp12_flow_mod, member flags). */
+enum ofp13_flow_mod_flags {
+    OFPFF13_NO_PKT_COUNTS = 1 << 3, /* Don’t keep track of packet count. */
+    OFPFF13_NO_BYT_COUNTS = 1 << 4  /* Don’t keep track of byte count. */
+};
+
+/* Common header for all meter bands */
+struct ofp13_meter_band_header {
+    ovs_be16 type;       /* One of OFPMBT_*. */
+    ovs_be16 len;        /* Length in bytes of this band. */
+    ovs_be32 rate;       /* Rate for this band. */
+    ovs_be32 burst_size; /* Size of bursts. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_band_header) == 12);
+
+/* Meter configuration. OFPT_METER_MOD. */
+struct ofp13_meter_mod {
+    ovs_be16          command;      /* One of OFPMC_*. */
+    ovs_be16          flags;        /* Set of OFPMF_*. */
+    ovs_be32          meter_id;     /* Meter instance. */
+    struct ofp13_meter_band_header bands[0];  /* The bands length is inferred
+                                                 from the length field in the
+                                                 header. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_mod) == 8);
+
+/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */
+enum ofp13_meter {
+    /* Last usable meter. */
+    OFPM13_MAX        = 0xffff0000,
+    /* Virtual meters. */
+    OFPM13_SLOWPATH   = 0xfffffffd, /* Meter for slow datapath. */
+    OFPM13_CONTROLLER = 0xfffffffe, /* Meter for controller connection. */
+    OFPM13_ALL        = 0xffffffff, /* Represents all meters for stat requests
+                                     commands. */
+};
+
+/* Meter commands */
+enum ofp13_meter_mod_command {
+    OFPMC13_ADD,           /* New meter. */
+    OFPMC13_MODIFY,        /* Modify specified meter. */
+    OFPMC13_DELETE         /* Delete specified meter. */
+};
+
+/* Meter configuration flags */
+enum ofp13_meter_flags {
+    OFPMF13_KBPS    = 1 << 0,   /* Rate value in kb/s (kilo-bit per second). */
+    OFPMF13_PKTPS   = 1 << 1,   /* Rate value in packet/sec. */
+    OFPMF13_BURST   = 1 << 2,   /* Do burst size. */
+    OFPMF13_STATS   = 1 << 3    /* Collect statistics. */
+};
+
+/* Meter band types */
+enum ofp13_meter_band_type {
+    OFPMBT13_DROP         = 1,     /* Drop packet. */
+    OFPMBT13_DSCP_REMARK  = 2,     /* Remark DSCP in the IP header. */
+    OFPMBT13_EXPERIMENTER = 0xFFFF /* Experimenter meter band. */
+};
+
+/* OFPMBT_DROP band - drop packets */
+struct ofp13_meter_band_drop {
+    ovs_be16    type;        /* OFPMBT_DROP. */
+    ovs_be16    len;         /* Length in bytes of this band. */
+    ovs_be32    rate;        /* Rate for dropping packets. */
+    ovs_be32    burst_size;  /* Size of bursts. */
+    uint8_t     pad[4];
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_band_drop) == 16);
+
+/* OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header */
+struct ofp13_meter_band_dscp_remark {
+    ovs_be16    type;        /* OFPMBT_DSCP_REMARK. */
+    ovs_be16    len;         /* Length in bytes of this band. */
+    ovs_be32    rate;        /* Rate for remarking packets. */
+    ovs_be32    burst_size;  /* Size of bursts. */
+    uint8_t     prec_level;  /* Number of drop precedence level to add. */
+    uint8_t     pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_band_dscp_remark) == 16);
+
+/* OFPMBT_EXPERIMENTER band - Write actions in action set */
+struct ofp13_meter_band_experimenter {
+    ovs_be16    type;        /* OFPMBT_EXPERIMENTER. */
+    ovs_be16    len;         /* Length in bytes of this band. */
+    ovs_be32    rate;        /* Rate for dropping packets. */
+    ovs_be32    burst_size;  /* Size of bursts. */
+    ovs_be32    experimenter; /* Experimenter ID which takes the same form as
+                                 in struct ofp_experimenter_header. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_band_experimenter) == 16);
+
+/* OF 1.3 adds MORE flag also for requests */
+enum ofp13_multipart_request_flags {
+    OFPMPF13_REQ_MORE = 1 << 0 /* More requests to follow. */
+};
+
+/* OF 1.3 splits table features off the ofp_table_stats */
+/* Body of reply to OFPMP13_TABLE request. */
+struct ofp13_table_stats {
+    uint8_t  table_id;      /* Identifier of table. Lower numbered tables are
+                               consulted first. */
+    uint8_t  pad[3];        /* Align to 32-bits. */
+    ovs_be32 active_count;  /* Number of active entries. */
+    ovs_be64 lookup_count;  /* Number of packets looked up in table. */
+    ovs_be64 matched_count; /* Number of packets that hit table. */
+};
+OFP_ASSERT(sizeof(struct ofp13_table_stats) == 24);
+
+/* Common header for all Table Feature Properties */
+struct ofp13_table_feature_prop_header {
+    ovs_be16    type;   /* One of OFPTFPT_*. */
+    ovs_be16    length; /* Length in bytes of this property. */
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_header) == 4);
+
+/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./
+ * Body of reply to OFPMP_TABLE_FEATURES request. */
+struct ofp13_table_features {
+    ovs_be16 length;          /* Length is padded to 64 bits. */
+    uint8_t table_id;         /* Identifier of table. Lower numbered tables
+                                 are consulted first. */
+    uint8_t pad[5];           /* Align to 64-bits. */
+    char name[OFP_MAX_TABLE_NAME_LEN];
+    ovs_be64 metadata_match;  /* Bits of metadata table can match. */
+    ovs_be64 metadata_write;  /* Bits of metadata table can write. */
+    ovs_be32 config;          /* Bitmap of OFPTC_* values */
+    ovs_be32 max_entries;     /* Max number of entries supported. */
+
+    /* Table Feature Property list */
+    struct ofp13_table_feature_prop_header properties[0];
+};
+OFP_ASSERT(sizeof(struct ofp13_table_features) == 64);
+
+/* Table Feature property types.
+ * Low order bit cleared indicates a property for a regular Flow Entry.
+ * Low order bit set indicates a property for the Table-Miss Flow Entry. */
+enum ofp13_table_feature_prop_type {
+    OFPTFPT13_INSTRUCTIONS         = 0, /* Instructions property. */
+    OFPTFPT13_INSTRUCTIONS_MISS    = 1, /* Instructions for table-miss. */
+    OFPTFPT13_NEXT_TABLES          = 2, /* Next Table property. */
+    OFPTFPT13_NEXT_TABLES_MISS     = 3, /* Next Table for table-miss. */
+    OFPTFPT13_WRITE_ACTIONS        = 4, /* Write Actions property. */
+    OFPTFPT13_WRITE_ACTIONS_MISS   = 5, /* Write Actions for table-miss. */
+    OFPTFPT13_APPLY_ACTIONS        = 6, /* Apply Actions property. */
+    OFPTFPT13_APPLY_ACTIONS_MISS   = 7, /* Apply Actions for table-miss. */
+    OFPTFPT13_MATCH                = 8, /* Match property. */
+    OFPTFPT13_WILDCARDS            = 10, /* Wildcards property. */
+    OFPTFPT13_WRITE_SETFIELD       = 12, /* Write Set-Field property. */
+    OFPTFPT13_WRITE_SETFIELD_MISS  = 13, /* Write Set-Field for table-miss. */
+    OFPTFPT13_APPLY_SETFIELD       = 14, /* Apply Set-Field property. */
+    OFPTFPT13_APPLY_SETFIELD_MISS  = 15, /* Apply Set-Field for table-miss. */
+    OFPTFPT13_EXPERIMENTER         = 0xFFFE, /* Experimenter property. */
+    OFPTFPT13_EXPERIMENTER_MISS    = 0xFFFF, /* Experimenter for table-miss. */
+};
+
+/* Instructions property */
+struct ofp13_table_feature_prop_instructions {
+    ovs_be16    type;    /* One of OFPTFPT13_INSTRUCTIONS,
+                            OFPTFPT13_INSTRUCTIONS_MISS. */
+    ovs_be16    length;  /* Length in bytes of this property. */
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the instruction ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    struct ofp11_instruction instruction_ids[0]; /* List of instructions
+                                                    without any data */
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_instructions) == 4);
+
+/* Next Tables property */
+struct ofp13_table_feature_prop_next_tables {
+    ovs_be16    type;   /* One of OFPTFPT13_NEXT_TABLES,
+                           OFPTFPT13_NEXT_TABLES_MISS. */
+    ovs_be16    length; /* Length in bytes of this property. */
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the table_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    uint8_t     next_table_ids[0];
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_next_tables) == 4);
+
+/* Actions property */
+struct ofp13_table_feature_prop_actions {
+    ovs_be16    type;   /* One of OFPTFPT13_WRITE_ACTIONS,
+                           OFPTFPT13_WRITE_ACTIONS_MISS,
+                           OFPTFPT13_APPLY_ACTIONS,
+                           OFPTFPT13_APPLY_ACTIONS_MISS. */
+    ovs_be16    length; /* Length in bytes of this property. */
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the action_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    struct ofp_action_header action_ids[0];     /* List of actions
+                                                   without any data */
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_actions) == 4);
+
+
+/* Match, Wildcard or Set-Field property */
+struct ofp13_table_feature_prop_oxm {
+    ovs_be16    type;   /* One of OFPTFPT13_MATCH, OFPTFPT13_WILDCARDS,
+                           OFPTFPT13_WRITE_SETFIELD,
+                           OFPTFPT13_WRITE_SETFIELD_MISS,
+                           OFPTFPT13_APPLY_SETFIELD,
+                           OFPTFPT13_APPLY_SETFIELD_MISS. */
+    ovs_be16    length; /* Length in bytes of this property. */
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the oxm_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    ovs_be32    oxm_ids[0];     /* Array of OXM headers */
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_oxm) == 4);
+
+/* Experimenter table feature property */
+struct ofp13_table_feature_prop_experimenter {
+    ovs_be16    type;     /* One of OFPTFPT13_EXPERIMENTER,
+                             OFPTFPT13_EXPERIMENTER_MISS. */
+    ovs_be16    length;   /* Length in bytes of this property. */
+    ovs_be32    experimenter; /* Experimenter ID which takes the same form
+                                 as in struct ofp_experimenter_header. */
+    ovs_be32    exp_type;     /* Experimenter defined. */
+    /* Followed by:
+     *   - Exactly (length - 12) bytes containing the experimenter data, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    ovs_be32    experimenter_data[0];
+};
+OFP_ASSERT(sizeof(struct ofp13_table_feature_prop_experimenter) == 12);
+
+/* Body of reply to OFPMP13_PORT request. If a counter is unsupported, set
+ * the field to all ones. */
+struct ofp13_port_stats {
+    struct ofp11_port_stats ps;
+    ovs_be32 duration_sec;    /* Time port has been alive in seconds. */
+    ovs_be32 duration_nsec;   /* Time port has been alive in nanoseconds
+                                 beyond duration_sec. */
+};
+OFP_ASSERT(sizeof(struct ofp13_port_stats) == 112);
+
+/* Body of reply to OFPMP13_QUEUE request */
+struct ofp13_queue_stats {
+    struct ofp11_queue_stats qs;
+    ovs_be32 duration_sec;    /* Time queue has been alive in seconds. */
+    ovs_be32 duration_nsec;   /* Time queue has been alive in nanoseconds
+                                 beyond duration_sec. */
+};
+OFP_ASSERT(sizeof(struct ofp13_queue_stats) == 40);
+
+/* Body of reply to OFPMP13_GROUP request */
+struct ofp13_group_stats {
+    struct ofp11_group_stats gs;
+    ovs_be32 duration_sec;    /* NEW: Time group has been alive in seconds. */
+    ovs_be32 duration_nsec;   /* NEW: Time group has been alive in nanoseconds
+                                 beyond duration_sec. */
+    /* struct ofp11_bucket_counter bucket_stats[0]; */
+};
+OFP_ASSERT(sizeof(struct ofp13_group_stats) == 40);
+
+/* Body of OFPMP13_METER and OFPMP13_METER_CONFIG requests. */
+struct ofp13_meter_multipart_request {
+    ovs_be32 meter_id;  /* Meter instance, or OFPM_ALL. */
+    uint8_t pad[4];     /* Align to 64 bits. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_multipart_request) == 8);
+
+/* Statistics for each meter band */
+struct ofp13_meter_band_stats {
+    ovs_be64    packet_band_count;      /* Number of packets in band. */
+    ovs_be64    byte_band_count;        /* Number of bytes in band. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_band_stats) == 16);
+
+/* Body of reply to OFPMP13_METER request. Meter statistics. */
+struct ofp13_meter_stats {
+    ovs_be32  meter_id;          /* Meter instance. */
+    ovs_be16  len;               /* Length in bytes of this stats. */
+    uint8_t   pad[6];
+    ovs_be32  flow_count;        /* Number of flows bound to meter. */
+    ovs_be64  packet_in_count;   /* Number of packets in input. */
+    ovs_be64  byte_in_count;     /* Number of bytes in input. */
+    ovs_be32  duration_sec;      /* Time meter has been alive in seconds. */
+    ovs_be32  duration_nsec;     /* Time meter has been alive in nanoseconds
+                                    beyond duration_sec. */
+    struct ofp13_meter_band_stats band_stats[0]; /* The band_stats length is
+                                             inferred from the length field. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 40);
+
+/* Body of reply to OFPMP13_METER_CONFIG request. Meter configuration. */
+struct ofp13_meter_config {
+    ovs_be16          length;       /* Length of this entry. */
+    ovs_be16          flags;        /* Set of OFPMC_* that apply. */
+    ovs_be32          meter_id;     /* Meter instance. */
+    struct ofp13_meter_band_header bands[0];  /* The bands length is inferred
+                                               from the length field. */
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_config) == 8);
+
+/* Body of reply to OFPMP13_METER_FEATURES request. Meter features. */
+struct ofp13_meter_features {
+    ovs_be32   max_meter;     /* Maximum number of meters. */
+    ovs_be32   band_types;    /* Bitmaps of OFPMBT13_* values supported. */
+    ovs_be32   capabilities;  /* Bitmaps of "ofp13_meter_flags". */
+    uint8_t    max_bands;     /* Maximum bands per meters */
+    uint8_t    max_color;     /* Maximum color value */
+    uint8_t    pad[2];
+};
+OFP_ASSERT(sizeof(struct ofp13_meter_features) == 16);
+
+/* Asynchronous message configuration. */
+/* The body of this is the same as nx_async_config */
+/* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */
+struct ofp13_async_config {
+    ovs_be32 packet_in_mask[2];   /* Bitmasks of OFPR_* values. */
+    ovs_be32 port_status_mask[2]; /* Bitmasks of OFPPR_* values. */
+    ovs_be32 flow_removed_mask[2];/* Bitmasks of OFPRR_* values. */
+};
+OFP_ASSERT(sizeof(struct ofp13_async_config) == 24);
+
+
+/* Packet received on port (datapath -> controller). */
+struct ofp13_packet_in {
+    struct ofp12_packet_in pi;
+    ovs_be64 cookie;          /* Cookie of the flow entry that was looked up */
+    /* Followed by:
+     *   - Match
+     *   - Exactly 2 all-zero padding bytes, then
+     *   - An Ethernet frame whose length is inferred from header.length.
+     * The padding bytes preceding the Ethernet frame ensure that the IP
+     * header (if any) following the Ethernet header is 32-bit aligned.
+     */
+    /* struct ofp12_match match; */
+    /* uint8_t pad[2];         Align to 64 bit + 16 bit */
+    /* uint8_t data[0];        Ethernet frame */
+};
+OFP_ASSERT(sizeof(struct ofp13_packet_in) == 16);
+
+
+#endif /* openflow/openflow-1.3.h */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index 462b2fc..d216f0e 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -75,6 +75,7 @@ enum ofp_version {
     OFP10_VERSION = 0x01,
     OFP11_VERSION = 0x02,
     OFP12_VERSION = 0x03,
+    OFP13_VERSION = 0x04
 };
 
 #define OFP_MAX_TABLE_NAME_LEN 32
@@ -166,14 +167,17 @@ struct ofp_switch_features {
     ovs_be32 n_buffers;     /* Max packets buffered at once. */
 
     uint8_t n_tables;       /* Number of tables supported by datapath. */
-    uint8_t pad[3];         /* Align to 64-bits. */
+    uint8_t auxiliary_id;   /* OF 1.3: Identify auxiliary connections */
+    uint8_t pad[2];         /* Align to 64-bits. */
 
     /* Features. */
     ovs_be32 capabilities;  /* OFPC_*, OFPC10_*, OFPC11_*, OFPC12_*. */
-    ovs_be32 actions;       /* Bitmap of supported "ofp_action_type"s. */
+    ovs_be32 actions;       /* Bitmap of supported "ofp_action_type"s.
+                             * DEPRECATED in OpenFlow 1.1 */
 
     /* Followed by an array of struct ofp10_phy_port or struct ofp11_port
-     * structures.  The number is inferred from header.length. */
+     * structures.  The number is inferred from header.length.
+     * REMOVED in OpenFlow 1.3 */
 };
 OFP_ASSERT(sizeof(struct ofp_switch_features) == 24);
 
diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
index b2516c0..d5a78fe 100644
--- a/include/openflow/openflow.h
+++ b/include/openflow/openflow.h
@@ -20,5 +20,6 @@
 #include "openflow/openflow-1.0.h"
 #include "openflow/openflow-1.1.h"
 #include "openflow/openflow-1.2.h"
+#include "openflow/openflow-1.3.h"
 
 #endif /* openflow/openflow.h */
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 5df05f3..0e0d779 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -366,13 +366,30 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
     case OFPTYPE_FLOW_MOD_TABLE_ID:
     case OFPTYPE_SET_PACKET_IN_FORMAT:
     case OFPTYPE_FLOW_AGE:
-    case OFPTYPE_SET_ASYNC_CONFIG:
     case OFPTYPE_SET_CONTROLLER_ID:
     case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
     case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
     case OFPTYPE_FLOW_MONITOR_CANCEL:
     case OFPTYPE_FLOW_MONITOR_PAUSED:
     case OFPTYPE_FLOW_MONITOR_RESUMED:
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_GET_ASYNC_REPLY:
+    case OFPTYPE_SET_ASYNC_CONFIG:
+    case OFPTYPE_METER_MOD:
+    case OFPTYPE_GROUP_REQUEST:
+    case OFPTYPE_GROUP_REPLY:
+    case OFPTYPE_GROUP_DESC_REQUEST:
+    case OFPTYPE_GROUP_DESC_REPLY:
+    case OFPTYPE_GROUP_FEATURES_REQUEST:
+    case OFPTYPE_GROUP_FEATURES_REPLY:
+    case OFPTYPE_METER_REQUEST:
+    case OFPTYPE_METER_REPLY:
+    case OFPTYPE_METER_CONFIG_REQUEST:
+    case OFPTYPE_METER_CONFIG_REPLY:
+    case OFPTYPE_METER_FEATURES_REQUEST:
+    case OFPTYPE_METER_FEATURES_REPLY:
+    case OFPTYPE_TABLE_FEATURES_REQUEST:
+    case OFPTYPE_TABLE_FEATURES_REPLY:
     default:
         if (VLOG_IS_DBG_ENABLED()) {
             char *s = ofp_to_string(msg->data, msg->size, 2);
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 837db8d..a3a8bc3 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1202,6 +1202,7 @@ nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
         struct ofp_header *oh = (struct ofp_header *)openflow->l2;
 
         switch(oh->version) {
+        case OFP13_VERSION:
         case OFP12_VERSION:
             set_field_to_ofast(load, openflow);
             break;
diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c
index 2c71312..9fd48fe 100644
--- a/lib/ofp-errors.c
+++ b/lib/ofp-errors.c
@@ -31,6 +31,8 @@ ofperr_domain_from_version(enum ofp_version version)
         return &ofperr_of11;
     case OFP12_VERSION:
         return &ofperr_of12;
+    case OFP13_VERSION:
+        return &ofperr_of13;
     default:
         return NULL;
     }
@@ -257,6 +259,7 @@ ofperr_encode_hello(enum ofperr error, enum ofp_version ofp_version,
     case OFP10_VERSION:
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         break;
 
     default:
diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
index ffac8aa..e9fedb9 100644
--- a/lib/ofp-errors.h
+++ b/lib/ofp-errors.h
@@ -130,6 +130,9 @@ enum ofperr {
     /* OF1.2+(1,12).  Invalid packet in packet-out. */
     OFPERR_OFPBRC_BAD_PACKET,
 
+    /* OF1.3+(1,13).  Multipart request overflowed the assigned buffer. */
+    OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW,
+
     /* NX1.0+(1,256).  Invalid NXM flow match. */
     OFPERR_NXBRC_NXM_INVALID,
 
@@ -492,6 +495,77 @@ enum ofperr {
     /* NX1.0(1,513), NX1.1(1,513), OF1.2+(11,2).  Invalid role. */
     OFPERR_OFPRRFC_BAD_ROLE,
 
+/* ## ---------------------- ## */
+/* ## OFPET_METER_MOD_FAILED ## */
+/* ## ---------------------- ## */
+
+    /* OF1.3+(12).  Error in meter. */
+    OFPERR_OFPET_METER_MOD_FAILED,
+
+    /* OF1.3+(12,0).  Unspecified error. */
+    OFPERR_OFPMMFC_UNKNOWN,
+
+    /* OF1.3+(12,1).  Meter not added because a Meter ADD attempted to
+     * replace an existing Meter. */
+    OFPERR_OFPMMFC_METER_EXISTS,
+
+    /* OF1.3+(12,2).  Meter not added because Meter specified is invalid. */
+    OFPERR_OFPMMFC_INVALID_METER,
+
+    /* OF1.3+(12,3).  Meter not modified because a Meter MODIFY attempted
+     * to modify a non-existent Meter. */
+    OFPERR_OFPMMFC_UNKNOWN_METER,
+
+    /* OF1.3+(12,4).  Unsupported or unknown command. */
+    OFPERR_OFPMMFC_BAD_COMMAND,
+
+    /* OF1.3+(12,5).  Flag configuration unsupported. */
+    OFPERR_OFPMMFC_BAD_FLAGS,
+
+    /* OF1.3+(12,6).  Rate unsupported. */
+    OFPERR_OFPMMFC_BAD_RATE,
+
+    /* OF1.3+(12,7).  Burst size unsupported. */
+    OFPERR_OFPMMFC_BAD_BURST,
+
+    /* OF1.3+(12,8).  Band unsupported. */
+    OFPERR_OFPMMFC_BAD_BAND,
+
+    /* OF1.3+(12,9).  Band value unsupported. */
+    OFPERR_OFPMMFC_BAD_BAND_VALUE,
+
+    /* OF1.3+(12,10).  No more meters available. */
+    OFPERR_OFPMMFC_OUT_OF_METERS,
+
+    /* OF1.3+(12,11).  The maximum number of properties for a meter has
+     * been exceeded. */
+    OFPERR_OFPMMFC_OUT_OF_BANDS,
+
+/* ## --------------------------- ## */
+/* ## OFPET_TABLE_FEATURES_FAILED ## */
+/* ## --------------------------- ## */
+
+    /* OF1.3+(13).  Setting table features failed. */
+    OFPERR_OFPET_TABLE_FEATURES_FAILED,
+
+    /* OF1.3+(13,0).  Specified table does not exist. */
+    OFPERR_OFPTFFC_BAD_TABLE,
+
+    /* OF1.3+(13,1).  Invalid metadata mask. */
+    OFPERR_OFPTFFC_BAD_METADATA,
+
+    /* OF1.3+(13,2).  Unknown property type. */
+    OFPERR_OFPTFFC_BAD_TYPE,
+
+    /* OF1.3+(13,3).  Length problem in properties. */
+    OFPERR_OFPTFFC_BAD_LEN,
+
+    /* OF1.3+(13,4).  Unsupported property value. */
+    OFPERR_OFPTFFC_BAD_ARGUMENT,
+
+    /* OF1.3+(13,5).  Permissions error. */
+    OFPERR_OFPTFFC_EPERM,
+
 /* ## ------------------ ## */
 /* ## OFPET_EXPERIMENTER ## */
 /* ## ------------------ ## */
diff --git a/lib/ofp-msgs.c b/lib/ofp-msgs.c
index 00e1a84..d0f5da6 100644
--- a/lib/ofp-msgs.c
+++ b/lib/ofp-msgs.c
@@ -265,6 +265,7 @@ ofphdrs_is_stat(const struct ofphdrs *hdrs)
                 hdrs->type == OFPT10_STATS_REPLY);
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         return (hdrs->type == OFPT11_STATS_REQUEST ||
                 hdrs->type == OFPT11_STATS_REPLY);
     }
@@ -291,6 +292,7 @@ ofphdrs_len(const struct ofphdrs *hdrs)
 
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         if (hdrs->type == OFPT11_STATS_REQUEST ||
             hdrs->type == OFPT11_STATS_REPLY) {
             return (hdrs->stat == OFPST_VENDOR
@@ -704,6 +706,7 @@ ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version)
         break;
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         assert(hdrs.type == OFPT11_STATS_REQUEST);
         hdrs.type = OFPT11_STATS_REPLY;
         break;
@@ -880,6 +883,7 @@ ofpmp_flags__(const struct ofp_header *oh)
         return &((struct ofp10_stats_msg *) oh)->flags;
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         return &((struct ofp11_stats_msg *) oh)->flags;
     default:
         NOT_REACHED();
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 557524d..496d120 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -128,8 +128,10 @@ enum ofpraw {
 
     /* OFPT 1.0 (6): struct ofp_switch_features, struct ofp10_phy_port[]. */
     OFPRAW_OFPT10_FEATURES_REPLY,
-    /* OFPT 1.1+ (6): struct ofp_switch_features, struct ofp11_port[]. */
+    /* OFPT 1.1-1.2 (6): struct ofp_switch_features, struct ofp11_port[]. */
     OFPRAW_OFPT11_FEATURES_REPLY,
+    /* OFPT 1.3+ (6): struct ofp_switch_features. */
+    OFPRAW_OFPT13_FEATURES_REPLY,
 
     /* OFPT 1.0+ (7): void. */
     OFPRAW_OFPT_GET_CONFIG_REQUEST,
@@ -146,6 +148,8 @@ enum ofpraw {
     OFPRAW_OFPT11_PACKET_IN,
     /* OFPT 1.2 (10): struct ofp12_packet_in, uint8_t[]. */
     OFPRAW_OFPT12_PACKET_IN,
+    /* OFPT 1.3 (10): struct ofp13_packet_in, uint8_t[]. */
+    OFPRAW_OFPT13_PACKET_IN,
     /* NXT 1.0+ (17): struct nx_packet_in, uint8_t[]. */
     OFPRAW_NXT_PACKET_IN,
 
@@ -188,6 +192,18 @@ enum ofpraw {
     /* OFPT 1.1+ (21): void. */
     OFPRAW_OFPT11_BARRIER_REPLY,
 
+    /* OFPT 1.3+ (26): void. */
+    OFPRAW_OFPT13_GET_ASYNC_REQUEST,
+    /* OFPT 1.3+ (27): struct ofp13_async_config. */
+    OFPRAW_OFPT13_GET_ASYNC_REPLY,
+    /* OFPT 1.3+ (28): struct ofp13_async_config. */
+    OFPRAW_OFPT13_SET_ASYNC,
+    /* NXT 1.0+ (19): struct nx_async_config. */
+    OFPRAW_NXT_SET_ASYNC_CONFIG,
+
+    /* OFPT 1.3+ (29): struct ofp13_meter_mod. */
+    OFPRAW_OFPT13_METER_MOD,
+
 /* Standard statistics. */
 
     /* OFPST 1.0+ (0): void. */
@@ -205,8 +221,10 @@ enum ofpraw {
 
     /* OFPST 1.0 (1): uint8_t[]. */
     OFPRAW_OFPST10_FLOW_REPLY,
-    /* OFPST 1.1+ (1): uint8_t[]. */
+    /* OFPST 1.1-1.2 (1): uint8_t[]. */
     OFPRAW_OFPST11_FLOW_REPLY,
+    /* OFPST 1.3+ (1): uint8_t[]. */
+    OFPRAW_OFPST13_FLOW_REPLY,
     /* NXST 1.0 (0): uint8_t[]. */
     OFPRAW_NXST_FLOW_REPLY,
 
@@ -222,7 +240,7 @@ enum ofpraw {
     /* NXST 1.0 (1): struct ofp_aggregate_stats_reply. */
     OFPRAW_NXST_AGGREGATE_REPLY,
 
-    /* OFPST 1.0-1.2 (3): void. */
+    /* OFPST 1.0+ (3): void. */
     OFPRAW_OFPST_TABLE_REQUEST,
 
     /* OFPST 1.0 (3): struct ofp10_table_stats[]. */
@@ -231,6 +249,8 @@ enum ofpraw {
     OFPRAW_OFPST11_TABLE_REPLY,
     /* OFPST 1.2 (3): struct ofp12_table_stats[]. */
     OFPRAW_OFPST12_TABLE_REPLY,
+    /* OFPST 1.3 (3): struct ofp13_table_stats[]. */
+    OFPRAW_OFPST13_TABLE_REPLY,
 
     /* OFPST 1.0 (4): struct ofp10_port_stats_request. */
     OFPRAW_OFPST10_PORT_REQUEST,
@@ -239,8 +259,10 @@ enum ofpraw {
 
     /* OFPST 1.0 (4): struct ofp10_port_stats[]. */
     OFPRAW_OFPST10_PORT_REPLY,
-    /* OFPST 1.1+ (4): struct ofp11_port_stats[]. */
+    /* OFPST 1.1-1.2 (4): struct ofp11_port_stats[]. */
     OFPRAW_OFPST11_PORT_REPLY,
+    /* OFPST 1.3+ (4): struct ofp13_port_stats[]. */
+    OFPRAW_OFPST13_PORT_REPLY,
 
     /* OFPST 1.0 (5): struct ofp10_queue_stats_request. */
     OFPRAW_OFPST10_QUEUE_REQUEST,
@@ -249,8 +271,54 @@ enum ofpraw {
 
     /* OFPST 1.0 (5): struct ofp10_queue_stats[]. */
     OFPRAW_OFPST10_QUEUE_REPLY,
-    /* OFPST 1.1+ (5): struct ofp11_queue_stats[]. */
+    /* OFPST 1.1-1.2 (5): struct ofp11_queue_stats[]. */
     OFPRAW_OFPST11_QUEUE_REPLY,
+    /* OFPST 1.3+ (5): struct ofp13_queue_stats[]. */
+    OFPRAW_OFPST13_QUEUE_REPLY,
+
+    /* OFPST 1.1+ (6): struct ofp11_group_stats_request. */
+    OFPRAW_OFPST11_GROUP_REQUEST,
+
+    /* OFPST 1.1-1.2 (6): struct ofp11_group_stats[]. */
+    OFPRAW_OFPST11_GROUP_REPLY,
+    /* OFPST 1.3 (6): struct ofp13_group_stats[]. */
+    OFPRAW_OFPST13_GROUP_REPLY,
+
+    /* OFPST 1.1+ (7): void. */
+    OFPRAW_OFPST11_GROUP_DESC_REQUEST,
+
+    /* OFPST 1.1+ (7): struct ofp11_group_desc_stats[]. */
+    OFPRAW_OFPST11_GROUP_DESC_REPLY,
+
+    /* OFPST 1.2+ (8): void. */
+    OFPRAW_OFPST12_GROUP_FEATURES_REQUEST,
+
+    /* OFPST 1.2+ (8): struct ofp12_group_features_stats. */
+    OFPRAW_OFPST12_GROUP_FEATURES_REPLY,
+
+    /* OFPST 1.3+ (9): struct ofp13_meter_multipart_request. */
+    OFPRAW_OFPST13_METER_REQUEST,
+
+    /* OFPST 1.3+ (9): struct ofp13_meter_stats[]. */
+    OFPRAW_OFPST13_METER_REPLY,
+
+    /* OFPST 1.3+ (10): struct ofp13_meter_multipart_request. */
+    OFPRAW_OFPST13_METER_CONFIG_REQUEST,
+
+    /* OFPST 1.3+ (10): struct ofp13_meter_config[]. */
+    OFPRAW_OFPST13_METER_CONFIG_REPLY,
+
+    /* OFPST 1.3+ (11): void. */
+    OFPRAW_OFPST13_METER_FEATURES_REQUEST,
+
+    /* OFPST 1.3+ (11): struct ofp13_meter_features. */
+    OFPRAW_OFPST13_METER_FEATURES_REPLY,
+
+    /* OFPST 1.3+ (12): struct ofp13_table_features[]. */
+    OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+
+    /* OFPST 1.3+ (12): struct ofp13_table_features[]. */
+    OFPRAW_OFPST13_TABLE_FEATURES_REPLY,
 
     /* OFPST 1.0+ (13): void. */
     OFPRAW_OFPST_PORT_DESC_REQUEST,
@@ -283,9 +351,6 @@ enum ofpraw {
     /* NXT 1.0+ (18): void. */
     OFPRAW_NXT_FLOW_AGE,
 
-    /* NXT 1.0+ (19): struct nx_async_config. */
-    OFPRAW_NXT_SET_ASYNC_CONFIG,
-
     /* NXT 1.0+ (20): struct nx_controller_id. */
     OFPRAW_NXT_SET_CONTROLLER_ID,
 
@@ -360,7 +425,8 @@ enum ofptype {
     /* Switch configuration messages. */
     OFPTYPE_FEATURES_REQUEST,    /* OFPRAW_OFPT_FEATURES_REQUEST. */
     OFPTYPE_FEATURES_REPLY,      /* OFPRAW_OFPT10_FEATURES_REPLY.
-                                  * OFPRAW_OFPT11_FEATURES_REPLY. */
+                                  * OFPRAW_OFPT11_FEATURES_REPLY.
+                                  * OFPRAW_OFPT13_FEATURES_REPLY. */
     OFPTYPE_GET_CONFIG_REQUEST,  /* OFPRAW_OFPT_GET_CONFIG_REQUEST. */
     OFPTYPE_GET_CONFIG_REPLY,    /* OFPRAW_OFPT_GET_CONFIG_REPLY. */
     OFPTYPE_SET_CONFIG,          /* OFPRAW_OFPT_SET_CONFIG. */
@@ -369,6 +435,7 @@ enum ofptype {
     OFPTYPE_PACKET_IN,           /* OFPRAW_OFPT10_PACKET_IN.
                                   * OFPRAW_OFPT11_PACKET_IN.
                                   * OFPRAW_OFPT12_PACKET_IN.
+                                  * OFPRAW_OFPT13_PACKET_IN.
                                   * OFPRAW_NXT_PACKET_IN. */
     OFPTYPE_FLOW_REMOVED,        /* OFPRAW_OFPT10_FLOW_REMOVED.
                                   * OFPRAW_OFPT11_FLOW_REMOVED.
@@ -391,6 +458,15 @@ enum ofptype {
     OFPTYPE_BARRIER_REPLY,       /* OFPRAW_OFPT10_BARRIER_REPLY.
                                   * OFPRAW_OFPT11_BARRIER_REPLY. */
 
+    /* Asynchronous message configuration. */
+    OFPTYPE_GET_ASYNC_REQUEST,    /* OFPRAW_OFPT13_GET_ASYNC_REQUEST. */
+    OFPTYPE_GET_ASYNC_REPLY,      /* OFPRAW_OFPT13_GET_ASYNC_REPLY. */
+    OFPTYPE_SET_ASYNC_CONFIG,     /* OFPRAW_NXT_SET_ASYNC_CONFIG.
+                                   * OFPRAW_OFPT13_SET_ASYNC. */
+
+    /* Meters and rate limiters configuration messages. */
+    OFPTYPE_METER_MOD,            /* OFPRAW_OFPT13_METER_MOD. */
+
     /* Statistics. */
     OFPTYPE_DESC_STATS_REQUEST,      /* OFPRAW_OFPST_DESC_REQUEST. */
     OFPTYPE_DESC_STATS_REPLY,        /* OFPRAW_OFPST_DESC_REPLY. */
@@ -399,6 +475,7 @@ enum ofptype {
                                       * OFPRAW_NXST_FLOW_REQUEST. */
     OFPTYPE_FLOW_STATS_REPLY,        /* OFPRAW_OFPST10_FLOW_REPLY.
                                       * OFPRAW_OFPST11_FLOW_REPLY.
+                                      * OFPRAW_OFPST13_FLOW_REPLY.
                                       * OFPRAW_NXST_FLOW_REPLY. */
     OFPTYPE_AGGREGATE_STATS_REQUEST, /* OFPRAW_OFPST10_AGGREGATE_REQUEST.
                                       * OFPRAW_OFPST11_AGGREGATE_REQUEST.
@@ -408,15 +485,48 @@ enum ofptype {
     OFPTYPE_TABLE_STATS_REQUEST,     /* OFPRAW_OFPST_TABLE_REQUEST. */
     OFPTYPE_TABLE_STATS_REPLY,       /* OFPRAW_OFPST10_TABLE_REPLY.
                                       * OFPRAW_OFPST11_TABLE_REPLY.
-                                      * OFPRAW_OFPST12_TABLE_REPLY. */
+                                      * OFPRAW_OFPST12_TABLE_REPLY.
+                                      * OFPRAW_OFPST13_TABLE_REPLY. */
     OFPTYPE_PORT_STATS_REQUEST,      /* OFPRAW_OFPST10_PORT_REQUEST.
                                       * OFPRAW_OFPST11_PORT_REQUEST. */
     OFPTYPE_PORT_STATS_REPLY,        /* OFPRAW_OFPST10_PORT_REPLY.
-                                      * OFPRAW_OFPST11_PORT_REPLY. */
+                                      * OFPRAW_OFPST11_PORT_REPLY.
+                                      * OFPRAW_OFPST13_PORT_REPLY. */
     OFPTYPE_QUEUE_STATS_REQUEST,     /* OFPRAW_OFPST10_QUEUE_REQUEST.
                                       * OFPRAW_OFPST11_QUEUE_REQUEST. */
     OFPTYPE_QUEUE_STATS_REPLY,       /* OFPRAW_OFPST10_QUEUE_REPLY.
-                                      * OFPRAW_OFPST11_QUEUE_REPLY. */
+                                      * OFPRAW_OFPST11_QUEUE_REPLY.
+                                      * OFPRAW_OFPST13_QUEUE_REPLY. */
+
+    OFPTYPE_GROUP_REQUEST,           /* OFPRAW_OFPST11_GROUP_REQUEST. */
+
+    OFPTYPE_GROUP_REPLY,             /* OFPRAW_OFPST11_GROUP_REPLY.
+                                      * OFPRAW_OFPST13_GROUP_REPLY. */
+
+    OFPTYPE_GROUP_DESC_REQUEST,      /* OFPRAW_OFPST11_GROUP_DESC_REQUEST. */
+
+    OFPTYPE_GROUP_DESC_REPLY,        /* OFPRAW_OFPST11_GROUP_DESC_REPLY. */
+
+    OFPTYPE_GROUP_FEATURES_REQUEST, /* OFPRAW_OFPST12_GROUP_FEATURES_REQUEST. */
+
+    OFPTYPE_GROUP_FEATURES_REPLY,    /* OFPRAW_OFPST12_GROUP_FEATURES_REPLY. */
+
+    OFPTYPE_METER_REQUEST,           /* OFPRAW_OFPST13_METER_REQUEST. */
+
+    OFPTYPE_METER_REPLY,             /* OFPRAW_OFPST13_METER_REPLY. */
+
+    OFPTYPE_METER_CONFIG_REQUEST,    /* OFPRAW_OFPST13_METER_CONFIG_REQUEST. */
+
+    OFPTYPE_METER_CONFIG_REPLY,      /* OFPRAW_OFPST13_METER_CONFIG_REPLY. */
+
+    OFPTYPE_METER_FEATURES_REQUEST, /* OFPRAW_OFPST13_METER_FEATURES_REQUEST. */
+
+    OFPTYPE_METER_FEATURES_REPLY,    /* OFPRAW_OFPST13_METER_FEATURES_REPLY. */
+
+    OFPTYPE_TABLE_FEATURES_REQUEST, /* OFPRAW_OFPST13_TABLE_FEATURES_REQUEST. */
+
+    OFPTYPE_TABLE_FEATURES_REPLY,    /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */
+
     OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
 
     OFPTYPE_PORT_DESC_STATS_REPLY,   /* OFPRAW_OFPST10_PORT_DESC_REPLY.
@@ -429,7 +539,6 @@ enum ofptype {
     OFPTYPE_FLOW_MOD_TABLE_ID,    /* OFPRAW_NXT_FLOW_MOD_TABLE_ID. */
     OFPTYPE_SET_PACKET_IN_FORMAT, /* OFPRAW_NXT_SET_PACKET_IN_FORMAT. */
     OFPTYPE_FLOW_AGE,             /* OFPRAW_NXT_FLOW_AGE. */
-    OFPTYPE_SET_ASYNC_CONFIG,     /* OFPRAW_NXT_SET_ASYNC_CONFIG. */
     OFPTYPE_SET_CONTROLLER_ID,    /* OFPRAW_NXT_SET_CONTROLLER_ID. */
 
     /* Flow monitor extension. */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 1d71370..d64d461 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -858,6 +858,12 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
             fm->flags |= OFPFF_SEND_FLOW_REM;
         } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
             fm->flags |= OFPFF_CHECK_OVERLAP;
+        } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
+            fm->flags |= OFPFF12_RESET_COUNTS;
+        } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
+            fm->flags |= OFPFF13_NO_PKT_COUNTS;
+        } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
+            fm->flags |= OFPFF13_NO_BYT_COUNTS;
         } else {
             char *value;
 
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 1e35fba..fcc6d25 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -492,8 +492,13 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
     }
 
     ds_put_format(string, " dpid:%016"PRIx64"\n", features.datapath_id);
-    ds_put_format(string, "n_tables:%"PRIu8", n_buffers:%"PRIu32"\n",
+
+    ds_put_format(string, "n_tables:%"PRIu8", n_buffers:%"PRIu32,
                   features.n_tables, features.n_buffers);
+    if (features.auxiliary_id) {
+        ds_put_format(string, ", auxiliary_id:%"PRIu8, features.auxiliary_id);
+    }
+    ds_put_char(string, '\n');
 
     ds_put_cstr(string, "capabilities: ");
     ofp_print_bit_names(string, features.capabilities,
@@ -510,6 +515,8 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
     case OFP11_VERSION:
     case OFP12_VERSION:
         break;
+    case OFP13_VERSION:
+        return; /* no ports in ofp13_switch_features */
     default:
         NOT_REACHED();
     }
@@ -673,6 +680,33 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
 }
 
 static void
+ofp_print_flow_flags(struct ds *s, uint16_t flags)
+{
+    if (flags & OFPFF_SEND_FLOW_REM) {
+        ds_put_cstr(s, "send_flow_rem ");
+    }
+    if (flags & OFPFF_CHECK_OVERLAP) {
+        ds_put_cstr(s, "check_overlap ");
+    }
+    if (flags & OFPFF12_RESET_COUNTS) {
+        ds_put_cstr(s, "reset_counts ");
+    }
+    if (flags & OFPFF13_NO_PKT_COUNTS) {
+        ds_put_cstr(s, "no_packet_counts ");
+    }
+    if (flags & OFPFF13_NO_BYT_COUNTS) {
+        ds_put_cstr(s, "no_byte_counts ");
+    }
+
+    flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP
+               | OFPFF12_RESET_COUNTS
+               | OFPFF13_NO_PKT_COUNTS | OFPFF13_NO_BYT_COUNTS);
+    if (flags) {
+        ds_put_format(s, "flags:0x%"PRIx16" ", flags);
+    }
+}
+
+static void
 ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
 {
     struct ofputil_flow_mod fm;
@@ -771,22 +805,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
         ds_put_char(s, ' ');
     }
     if (fm.flags != 0) {
-        uint16_t flags = fm.flags;
-
-        if (flags & OFPFF_SEND_FLOW_REM) {
-            ds_put_cstr(s, "send_flow_rem ");
-        }
-        if (flags & OFPFF_CHECK_OVERLAP) {
-            ds_put_cstr(s, "check_overlap ");
-        }
-        if (flags & OFPFF10_EMERG) {
-            ds_put_cstr(s, "emerg ");
-        }
-
-        flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF10_EMERG);
-        if (flags) {
-            ds_put_format(s, "flags:0x%"PRIx16" ", flags);
-        }
+        ofp_print_flow_flags(s, fm.flags);
     }
 
     ofpacts_format(fm.ofpacts, fm.ofpacts_len, s);
@@ -1028,6 +1047,9 @@ ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
     if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
         ds_put_format(string, "hard_timeout=%"PRIu16", ", fs->hard_timeout);
     }
+    if (fs->flags) {
+        ofp_print_flow_flags(string, fs->flags);
+    }
     if (fs->idle_age >= 0) {
         ds_put_format(string, "idle_age=%d, ", fs->idle_age);
     }
@@ -1166,6 +1188,11 @@ ofp_print_one_ofpst_table_reply(struct ds *string, enum ofp_version ofp_version,
 {
     char name_[OFP_MAX_TABLE_NAME_LEN + 1];
 
+    /* ofp13_table_stats is different */
+    if (ofp_version > OFP12_VERSION) {
+        return;
+    }
+
     ovs_strlcpy(name_, name, sizeof name_);
 
     ds_put_format(string, "  %d: %-8s: ", ts->table_id, name_);
@@ -1210,6 +1237,36 @@ ofp_print_one_ofpst_table_reply(struct ds *string, enum ofp_version ofp_version,
 }
 
 static void
+ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh,
+                              int verbosity)
+{
+    struct ofp13_table_stats *ts;
+    struct ofpbuf b;
+    size_t n;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    n = b.size / sizeof *ts;
+    ds_put_format(string, " %zu tables\n", n);
+    if (verbosity < 1) {
+        return;
+    }
+
+    for (;;) {
+        ts = ofpbuf_try_pull(&b, sizeof *ts);
+        if (!ts) {
+            return;
+        }
+        ds_put_format(string,
+                      "  %d: active=%"PRIu32", lookup=%"PRIu64  \
+                      ", matched=%"PRIu64"\n",
+                      ts->table_id, ntohl(ts->active_count),
+                      ntohll(ts->lookup_count), ntohll(ts->matched_count));
+    }
+}
+
+static void
 ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh,
                               int verbosity)
 {
@@ -1316,6 +1373,10 @@ ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
                             int verbosity)
 {
     switch ((enum ofp_version)oh->version) {
+    case OFP13_VERSION:
+        ofp_print_ofpst_table_reply13(string, oh, verbosity);
+        break;
+
     case OFP12_VERSION:
         ofp_print_ofpst_table_reply12(string, oh, verbosity);
         break;
@@ -1722,6 +1783,9 @@ ofp_print_version(const struct ofp_header *oh,
     case OFP12_VERSION:
         ds_put_cstr(string, " (OF1.2)");
         break;
+    case OFP13_VERSION:
+        ds_put_cstr(string, " (OF1.3)");
+        break;
     default:
         ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
         break;
@@ -1738,6 +1802,12 @@ ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw,
 }
 
 static void
+ofp_print_not_implemented(struct ds *string)
+{
+    ds_put_cstr(string, "NOT IMPLEMENTED YET!\n");
+}
+
+static void
 ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
                 struct ds *string, int verbosity)
 {
@@ -1745,6 +1815,28 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
 
     ofp_header_to_string__(oh, raw, string);
     switch (ofptype_from_ofpraw(raw)) {
+
+        /* FIXME: Change the following once they are implemented: */
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_GET_ASYNC_REPLY:
+    case OFPTYPE_METER_MOD:
+    case OFPTYPE_GROUP_REQUEST:
+    case OFPTYPE_GROUP_REPLY:
+    case OFPTYPE_GROUP_DESC_REQUEST:
+    case OFPTYPE_GROUP_DESC_REPLY:
+    case OFPTYPE_GROUP_FEATURES_REQUEST:
+    case OFPTYPE_GROUP_FEATURES_REPLY:
+    case OFPTYPE_METER_REQUEST:
+    case OFPTYPE_METER_REPLY:
+    case OFPTYPE_METER_CONFIG_REQUEST:
+    case OFPTYPE_METER_CONFIG_REPLY:
+    case OFPTYPE_METER_FEATURES_REQUEST:
+    case OFPTYPE_METER_FEATURES_REPLY:
+    case OFPTYPE_TABLE_FEATURES_REQUEST:
+    case OFPTYPE_TABLE_FEATURES_REPLY:
+        ofp_print_not_implemented(string);
+        break;
+
     case OFPTYPE_HELLO:
         ofp_print_hello(string, oh);
         break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index bab6b2c..c2da878 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -607,6 +607,8 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
         return OFPUTIL_P_OF10_STD;
     case OFP12_VERSION:
         return OFPUTIL_P_OF12_OXM;
+    case OFP13_VERSION:
+        return OFPUTIL_P_OF13_OXM;
     case OFP11_VERSION:
     default:
         return 0;
@@ -614,7 +616,7 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
 }
 
 /* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION,
- * OFP11_VERSION or OFP12_VERSION) that corresponds to 'protocol'. */
+ * etc.) that corresponds to 'protocol'. */
 enum ofp_version
 ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
 {
@@ -626,6 +628,8 @@ ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
         return OFP10_VERSION;
     case OFPUTIL_P_OF12_OXM:
         return OFP12_VERSION;
+    case OFPUTIL_P_OF13_OXM:
+        return OFP13_VERSION;
     }
 
     NOT_REACHED();
@@ -664,6 +668,9 @@ ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
     case OFPUTIL_P_OF12_OXM:
         return OFPUTIL_P_OF12_OXM;
 
+    case OFPUTIL_P_OF13_OXM:
+        return OFPUTIL_P_OF13_OXM;
+
     default:
         NOT_REACHED();
     }
@@ -698,6 +705,9 @@ ofputil_protocol_set_base(enum ofputil_protocol cur,
     case OFPUTIL_P_OF12_OXM:
         return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid);
 
+    case OFPUTIL_P_OF13_OXM:
+        return ofputil_protocol_set_tid(OFPUTIL_P_OF13_OXM, tid);
+
     default:
         NOT_REACHED();
     }
@@ -728,6 +738,9 @@ ofputil_protocol_to_string(enum ofputil_protocol protocol)
 
     case OFPUTIL_P_OF12_OXM:
         return "OXM";
+
+    case OFPUTIL_P_OF13_OXM:
+        return "OpenFlow13";
     }
 
     /* Check abbreviations. */
@@ -860,6 +873,9 @@ ofputil_version_from_string(const char *s)
     if (!strcasecmp(s, "OpenFlow12")) {
         return OFP12_VERSION;
     }
+    if (!strcasecmp(s, "OpenFlow13")) {
+        return OFP13_VERSION;
+    }
     return 0;
 }
 
@@ -928,6 +944,8 @@ ofputil_version_to_string(enum ofp_version ofp_version)
         return "OpenFlow11";
     case OFP12_VERSION:
         return "OpenFlow12";
+    case OFP13_VERSION:
+        return "OpenFlow13";
     default:
         NOT_REACHED();
     }
@@ -1269,8 +1287,9 @@ ofputil_encode_set_protocol(enum ofputil_protocol current,
             return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
 
         case OFPUTIL_P_OF12_OXM:
-            /* There's only one OpenFlow 1.2 protocol and we already verified
-             * above that we're not trying to change versions. */
+        case OFPUTIL_P_OF13_OXM:
+            /* There are only one of each OpenFlow 1.2+ protocols and we already
+             * verified above that we're not trying to change versions. */
             NOT_REACHED();
 
         case OFPUTIL_P_OF10_STD_TID:
@@ -1511,6 +1530,16 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             NOT_REACHED();
         }
 
+        if (fm->flags & OFPFF10_EMERG) {
+            /* We do not support the OpenFlow 1.0 emergency flow cache, which
+             * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
+             * There is no good error code, so just state that the flow table
+             * is full.
+             * Moreover, OFPFF10_EMERG overlaps with OFPFF12_RESET_COUNTS,
+             * so this check must be here */
+            return OFPERR_OFPFMFC_TABLE_FULL;
+        }
+
         if (protocol & OFPUTIL_P_TID) {
             fm->command = command & 0xff;
             fm->table_id = command >> 8;
@@ -1544,10 +1573,12 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     struct ofpbuf *msg;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12_OXM: {
+    case OFPUTIL_P_OF12_OXM:
+    case OFPUTIL_P_OF13_OXM: {
         struct ofp11_flow_mod *ofm;
 
-        msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION,
+        msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, 
+                           ofputil_protocol_to_ofp_version(protocol),
                            NXM_TYPICAL_LEN + fm->ofpacts_len);
         ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
         if (fm->command == OFPFC_ADD) {
@@ -1764,13 +1795,15 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     enum ofpraw raw;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12_OXM: {
+    case OFPUTIL_P_OF12_OXM:
+    case OFPUTIL_P_OF13_OXM: {
         struct ofp11_flow_stats_request *ofsr;
 
         raw = (fsr->aggregate
                ? OFPRAW_OFPST11_AGGREGATE_REQUEST
                : OFPRAW_OFPST11_FLOW_REQUEST);
-        msg = ofpraw_alloc(raw, OFP12_VERSION, NXM_TYPICAL_LEN);
+        msg = ofpraw_alloc(raw, ofputil_protocol_to_ofp_version(protocol),
+			   NXM_TYPICAL_LEN);
         ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
         ofsr->table_id = fsr->table_id;
         ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port);
@@ -1878,7 +1911,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
 
     if (!msg->size) {
         return EOF;
-    } else if (raw == OFPRAW_OFPST11_FLOW_REPLY) {
+    } else if (raw == OFPRAW_OFPST11_FLOW_REPLY
+               || raw == OFPRAW_OFPST13_FLOW_REPLY) {
         const struct ofp11_flow_stats *ofs;
         size_t length;
         uint16_t padded_match_len;
@@ -1914,6 +1948,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         fs->duration_nsec = ntohl(ofs->duration_nsec);
         fs->idle_timeout = ntohs(ofs->idle_timeout);
         fs->hard_timeout = ntohs(ofs->hard_timeout);
+        fs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? ntohs(ofs->flags) : 0;
         fs->idle_age = -1;
         fs->hard_age = -1;
         fs->cookie = ofs->cookie;
@@ -1953,6 +1988,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         fs->hard_age = -1;
         fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count));
         fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
+        fs->flags = 0;
     } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
         const struct nx_flow_stats *nfs;
         size_t match_len, actions_len, length;
@@ -1999,6 +2035,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         }
         fs->packet_count = ntohll(nfs->packet_count);
         fs->byte_count = ntohll(nfs->byte_count);
+        fs->flags = 0;
     } else {
         NOT_REACHED();
     }
@@ -2031,7 +2068,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
     enum ofpraw raw;
 
     ofpraw_decode_partial(&raw, reply->data, reply->size);
-    if (raw == OFPRAW_OFPST11_FLOW_REPLY) {
+    if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
         struct ofp11_flow_stats *ofs;
 
         ofpbuf_put_uninit(reply, sizeof *ofs);
@@ -2048,6 +2085,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         ofs->priority = htons(fs->priority);
         ofs->idle_timeout = htons(fs->idle_timeout);
         ofs->hard_timeout = htons(fs->hard_timeout);
+        ofs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? htons(fs->flags) : 0;
         memset(ofs->pad2, 0, sizeof ofs->pad2);
         ofs->cookie = fs->cookie;
         ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
@@ -2247,7 +2285,8 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     struct ofpbuf *msg;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12_OXM: {
+    case OFPUTIL_P_OF12_OXM:
+    case OFPUTIL_P_OF13_OXM: {
         struct ofp12_flow_removed *ofr;
 
         msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
@@ -2341,12 +2380,19 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
-    if (raw == OFPRAW_OFPT12_PACKET_IN) {
-        const struct ofp12_packet_in *opi;
+    if (raw == OFPRAW_OFPT13_PACKET_IN || raw == OFPRAW_OFPT12_PACKET_IN) {
+        const struct ofp13_packet_in *opi;
         struct match match;
         int error;
+        size_t packet_in_size;
+
+        if (raw == OFPRAW_OFPT12_PACKET_IN) {
+            packet_in_size = sizeof (struct ofp12_packet_in);
+        } else {
+            packet_in_size = sizeof (struct ofp13_packet_in);
+        }
 
-        opi = ofpbuf_pull(&b, sizeof *opi);
+        opi = ofpbuf_pull(&b, packet_in_size);
         error = oxm_pull_match_loose(&b, &match);
         if (error) {
             return error;
@@ -2356,11 +2402,14 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
             return OFPERR_OFPBRC_BAD_LEN;
         }
 
-        pin->reason = opi->reason;
-        pin->table_id = opi->table_id;
+        pin->reason = opi->pi.reason;
+        pin->table_id = opi->pi.table_id;
+        pin->buffer_id = ntohl(opi->pi.buffer_id);
+        pin->total_len = ntohs(opi->pi.total_len);
 
-        pin->buffer_id = ntohl(opi->buffer_id);
-        pin->total_len = ntohs(opi->total_len);
+        if (raw == OFPRAW_OFPT13_PACKET_IN) {
+            pin->cookie = opi->cookie;
+        }
 
         ofputil_decode_packet_in_finish(pin, &match, &b);
     } else if (raw == OFPRAW_OFPT10_PACKET_IN) {
@@ -2440,27 +2489,43 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
     struct ofpbuf *packet;
 
     /* Add OFPT_PACKET_IN. */
-    if (protocol == OFPUTIL_P_OF12_OXM) {
-        struct ofp12_packet_in *opi;
+    if (protocol == OFPUTIL_P_OF13_OXM || protocol == OFPUTIL_P_OF12_OXM) {
+        struct ofp13_packet_in *opi;
         struct match match;
+        enum ofpraw packet_in_raw;
+        enum ofp_version packet_in_version;
+        size_t packet_in_size;
+
+        if (protocol == OFPUTIL_P_OF12_OXM) {
+            packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
+            packet_in_version = OFP12_VERSION;
+            packet_in_size = sizeof (struct ofp12_packet_in);
+        } else {
+            packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
+            packet_in_version = OFP13_VERSION;
+            packet_in_size = sizeof (struct ofp13_packet_in);
+        }
 
         ofputil_packet_in_to_match(pin, &match);
 
         /* The final argument is just an estimate of the space required. */
-        packet = ofpraw_alloc_xid(OFPRAW_OFPT12_PACKET_IN, OFP12_VERSION,
+        packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
                                   htonl(0), (sizeof(struct flow_metadata) * 2
                                              + 2 + send_len));
-        ofpbuf_put_zeros(packet, sizeof *opi);
+        ofpbuf_put_zeros(packet, packet_in_size);
         oxm_put_match(packet, &match);
         ofpbuf_put_zeros(packet, 2);
         ofpbuf_put(packet, pin->packet, send_len);
 
         opi = packet->l3;
-        opi->buffer_id = htonl(pin->buffer_id);
-        opi->total_len = htons(pin->total_len);
-        opi->reason = pin->reason;
-        opi->table_id = pin->table_id;
-   } else if (packet_in_format == NXPIF_OPENFLOW10) {
+        opi->pi.buffer_id = htonl(pin->buffer_id);
+        opi->pi.total_len = htons(pin->total_len);
+        opi->pi.reason = pin->reason;
+        opi->pi.table_id = pin->table_id;
+        if (protocol == OFPUTIL_P_OF13_OXM) {
+            opi->cookie = pin->cookie;
+        }
+    } else if (packet_in_format == NXPIF_OPENFLOW10) {
         struct ofp_packet_in *opi;
 
         packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
@@ -2729,6 +2794,7 @@ ofputil_get_phy_port_size(enum ofp_version ofp_version)
         return sizeof(struct ofp10_phy_port);
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         return sizeof(struct ofp11_port);
     default:
         NOT_REACHED();
@@ -2791,7 +2857,8 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
     }
 
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_port *op;
         if (b->size + sizeof *op <= UINT16_MAX) {
             op = ofpbuf_put_uninit(b, sizeof *op);
@@ -2820,7 +2887,8 @@ ofputil_append_port_desc_stats_reply(enum ofp_version ofp_version,
     }
 
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_port *op;
 
         op = ofpmp_append(replies, sizeof *op);
@@ -2889,6 +2957,7 @@ ofputil_capabilities_mask(enum ofp_version ofp_version)
     case OFP11_VERSION:
         return OFPC_COMMON | OFPC_ARP_MATCH_IP;
     case OFP12_VERSION:
+    case OFP13_VERSION:
         return OFPC_COMMON | OFPC12_PORT_BLOCKED;
     default:
         /* Caller needs to check osf->header.version itself */
@@ -2916,6 +2985,7 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
     features->datapath_id = ntohll(osf->datapath_id);
     features->n_buffers = ntohl(osf->n_buffers);
     features->n_tables = osf->n_tables;
+    features->auxiliary_id = 0;
 
     features->capabilities = ntohl(osf->capabilities) &
         ofputil_capabilities_mask(oh->version);
@@ -2929,11 +2999,15 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
             features->capabilities |= OFPUTIL_C_STP;
         }
         features->actions = decode_action_bits(osf->actions, of10_action_bits);
-    } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY) {
+    } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY
+               || raw == OFPRAW_OFPT13_FEATURES_REPLY) {
         if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
             features->capabilities |= OFPUTIL_C_GROUP_STATS;
         }
         features->actions = 0;
+        if (raw == OFPRAW_OFPT13_FEATURES_REPLY) {
+            features->auxiliary_id = osf->auxiliary_id;
+        }
     } else {
         return OFPERR_OFPBRC_BAD_VERSION;
     }
@@ -3010,6 +3084,9 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
     case OFP12_VERSION:
         raw = OFPRAW_OFPT11_FEATURES_REPLY;
         break;
+    case OFP13_VERSION:
+        raw = OFPRAW_OFPT13_FEATURES_REPLY;
+        break;
     default:
         NOT_REACHED();
     }
@@ -3029,6 +3106,9 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
         }
         osf->actions = encode_action_bits(features->actions, of10_action_bits);
         break;
+    case OFP13_VERSION:
+        osf->auxiliary_id = features->auxiliary_id;
+        /* fall through */
     case OFP11_VERSION:
     case OFP12_VERSION:
         if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
@@ -3102,6 +3182,7 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps,
 
     case OFP11_VERSION:
     case OFP12_VERSION:
+    case OFP13_VERSION:
         raw = OFPRAW_OFPT11_PORT_STATUS;
         break;
 
@@ -3185,7 +3266,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     }
 
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_port_mod *opm;
 
         b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
@@ -3309,6 +3391,22 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
     out->matched_count = in->matched_count;
 }
 
+static void
+ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
+                              struct ofpbuf *buf)
+{
+    struct ofp13_table_stats *out;
+
+    /* OF 1.3 splits table features off the ofp_table_stats,
+     * so there is not much here. */
+
+    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out->table_id = in->table_id;
+    out->active_count = in->active_count;
+    out->lookup_count = in->lookup_count;
+    out->matched_count = in->matched_count;
+}
+
 struct ofpbuf *
 ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
                                  const struct ofp_header *request)
@@ -3335,6 +3433,12 @@ ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
         ofpbuf_put(reply, stats, n * sizeof *stats);
         break;
 
+    case OFP13_VERSION:
+        for (i = 0; i < n; i++) {
+            ofputil_put_ofp13_table_stats(&stats[i], reply);
+        }
+        break;
+
     default:
         NOT_REACHED();
     }
@@ -3631,7 +3735,8 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
     }
 
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_packet_out *opo;
         size_t len;
 
@@ -3689,6 +3794,7 @@ ofputil_encode_barrier_request(enum ofp_version ofp_version)
     enum ofpraw type;
 
     switch (ofp_version) {
+    case OFP13_VERSION:
     case OFP12_VERSION:
     case OFP11_VERSION:
         type = OFPRAW_OFPT11_BARRIER_REQUEST;
@@ -3920,7 +4026,8 @@ ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
         return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
     }
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
         return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
     }
@@ -4219,7 +4326,7 @@ ofputil_parse_key_value(char **stringp, char **keyp, char **valuep)
 }
 
 /* Encode a dump ports request for 'port', the encoded message
- * will be fore Open Flow version 'ofp_version'. Returns message
+ * will be for Open Flow version 'ofp_version'. Returns message
  * as a struct ofpbuf. Returns encoded message on success, NULL on error */
 struct ofpbuf *
 ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
@@ -4235,7 +4342,8 @@ ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
         break;
     }
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_port_stats_request *req;
         request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
         req = ofpbuf_put_zeros(request, sizeof *req);
@@ -4289,6 +4397,19 @@ ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
     ps11->collisions = htonll(ops->stats.collisions);
 }
 
+static void
+ofputil_port_stats_to_ofp13(const struct ofputil_port_stats *ops,
+                            struct ofp13_port_stats *ps13)
+{
+    ofputil_port_stats_to_ofp11(ops, &ps13->ps);
+
+    /* OF 1.3 adds duration fields */
+    /* FIXME: Need to implement port alive duration (sec + nsec) */
+    ps13->duration_sec = htonl(~0);
+    ps13->duration_nsec = htonl(~0);
+}
+
+
 /* Encode a ports stat for 'ops' and append it to 'replies'. */
 void
 ofputil_append_port_stat(struct list *replies,
@@ -4298,6 +4419,11 @@ ofputil_append_port_stat(struct list *replies,
     struct ofp_header *oh = msg->data;
 
     switch ((enum ofp_version)oh->version) {
+    case OFP13_VERSION: {
+        struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+        ofputil_port_stats_to_ofp13(ops, reply);
+        break;
+    }
     case OFP12_VERSION:
     case OFP11_VERSION: {
         struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
@@ -4368,6 +4494,21 @@ ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
     return 0;
 }
 
+static enum ofperr
+ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
+                              const struct ofp13_port_stats *ps13)
+{
+    enum ofperr error =
+        ofputil_port_stats_from_ofp11(ops, &ps13->ps);
+    if (!error) {
+        /* FIXME: Get ps13->duration_sec and ps13->duration_nsec,
+         * Add to netdev_stats? */
+    }
+
+    return error;
+}
+
+
 /* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
  * message 'oh'. */
 size_t
@@ -4408,14 +4549,20 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
 
     if (!msg->size) {
         return EOF;
+    } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
+        const struct ofp13_port_stats *ps13;
+
+        ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
+        if (!ps13) {
+            goto bad_len;
+        }
+        return ofputil_port_stats_from_ofp13(ps, ps13);
     } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
         const struct ofp11_port_stats *ps11;
 
         ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
         if (!ps11) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
-                         "bytes at end", msg->size);
-            return OFPERR_OFPBRC_BAD_LEN;
+            goto bad_len;
         }
         return ofputil_port_stats_from_ofp11(ps, ps11);
     } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
@@ -4423,15 +4570,17 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
 
         ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
         if (!ps10) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
-                         "bytes at end", msg->size);
-            return OFPERR_OFPBRC_BAD_LEN;
+            goto bad_len;
         }
         return ofputil_port_stats_from_ofp10(ps, ps10);
     } else {
         NOT_REACHED();
     }
 
+ bad_len:
+    VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
+                 "bytes at end", msg->size);
+    return OFPERR_OFPBRC_BAD_LEN;
 }
 
 /* Parse a port status request message into a 16 bit OpenFlow 1.0
@@ -4442,6 +4591,7 @@ ofputil_decode_port_stats_request(const struct ofp_header *request,
                                   uint16_t *ofp10_port)
 {
     switch ((enum ofp_version)request->version) {
+    case OFP13_VERSION:
     case OFP12_VERSION:
     case OFP11_VERSION: {
         const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
@@ -4466,6 +4616,7 @@ ofputil_decode_queue_stats_request(const struct ofp_header *request,
                                    struct ofputil_queue_stats_request *oqsr)
 {
     switch ((enum ofp_version)request->version) {
+    case OFP13_VERSION:
     case OFP12_VERSION:
     case OFP11_VERSION: {
         const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
@@ -4500,7 +4651,8 @@ ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
 
     switch (ofp_version) {
     case OFP11_VERSION:
-    case OFP12_VERSION: {
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
         struct ofp11_queue_stats_request *req;
         request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
         req = ofpbuf_put_zeros(request, sizeof *req);
@@ -4572,6 +4724,20 @@ ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
     return 0;
 }
 
+static enum ofperr
+ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
+                               const struct ofp13_queue_stats *qs13)
+{
+    enum ofperr error
+        = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
+    if (!error) {
+        /* FIXME: Get qs13->duration_sec and qs13->duration_nsec,
+         * Add to netdev_queue_stats? */
+    }
+
+    return error;
+}
+
 /* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
  * ofputil_queue_stats in 'qs'.
  *
@@ -4597,14 +4763,20 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
 
     if (!msg->size) {
         return EOF;
+    } else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
+        const struct ofp13_queue_stats *qs13;
+
+        qs13 = ofpbuf_try_pull(msg, sizeof *qs13);
+        if (!qs13) {
+            goto bad_len;
+        }
+        return ofputil_queue_stats_from_ofp13(qs, qs13);
     } else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
         const struct ofp11_queue_stats *qs11;
 
         qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
         if (!qs11) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
-                         "bytes at end", msg->size);
-            return OFPERR_OFPBRC_BAD_LEN;
+            goto bad_len;
         }
         return ofputil_queue_stats_from_ofp11(qs, qs11);
     } else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
@@ -4612,14 +4784,17 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
 
         qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
         if (!qs10) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
-                         "bytes at end", msg->size);
-            return OFPERR_OFPBRC_BAD_LEN;
+            goto bad_len;
         }
         return ofputil_queue_stats_from_ofp10(qs, qs10);
     } else {
         NOT_REACHED();
     }
+
+ bad_len:
+    VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
+                 "bytes at end", msg->size);
+    return OFPERR_OFPBRC_BAD_LEN;
 }
 
 static void
@@ -4645,6 +4820,17 @@ ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
     qs11->tx_errors = htonll(oqs->stats.tx_errors);
 }
 
+static void
+ofputil_queue_stats_to_ofp13(const struct ofputil_queue_stats *oqs,
+                             struct ofp13_queue_stats *qs13)
+{
+    ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
+    /* OF 1.3 adds duration fields */
+    /* FIXME: Need to implement queue alive duration (sec + nsec) */
+    qs13->duration_sec = htonl(~0);
+    qs13->duration_nsec = htonl(~0);
+}
+
 /* Encode a queue stat for 'oqs' and append it to 'replies'. */
 void
 ofputil_append_queue_stat(struct list *replies,
@@ -4654,15 +4840,21 @@ ofputil_append_queue_stat(struct list *replies,
     struct ofp_header *oh = msg->data;
 
     switch ((enum ofp_version)oh->version) {
+    case OFP13_VERSION: {
+        struct ofp13_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
+        ofputil_queue_stats_to_ofp13(oqs, reply);
+        break;
+    }
+
     case OFP12_VERSION:
     case OFP11_VERSION: {
-        struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+        struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
         ofputil_queue_stats_to_ofp11(oqs, reply);
         break;
     }
 
     case OFP10_VERSION: {
-        struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+        struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
         ofputil_queue_stats_to_ofp10(oqs, reply);
         break;
     }
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 053cd84..630dfc9 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -77,22 +77,24 @@ enum ofputil_protocol {
 #define OFPUTIL_P_OF10_STD_ANY (OFPUTIL_P_OF10_STD | OFPUTIL_P_OF10_STD_TID)
 #define OFPUTIL_P_OF10_NXM_ANY (OFPUTIL_P_OF10_NXM | OFPUTIL_P_OF10_NXM_TID)
 
-    /* OpenFlow 1.2 protocol (only one variant).
+    /* OpenFlow 1.2+ protocols (only one variant each).
      *
-     * This uses the standard OpenFlow Extensible Match (OXM) flow format.
+     * These use the standard OpenFlow Extensible Match (OXM) flow format.
      *
-     * OpenFlow 1.2 always operates with an equivalent of the
+     * OpenFlow 1.2+ always operates with an equivalent of the
      * nx_flow_mod_table_id Nicira extension enabled, so there is no "TID"
      * variant. */
     OFPUTIL_P_OF12_OXM      = 1 << 4,
+    OFPUTIL_P_OF13_OXM      = 1 << 5,
 
     /* All protocols. */
-#define OFPUTIL_P_ANY ((1 << 5) - 1)
+#define OFPUTIL_P_ANY ((1 << 6) - 1)
 
     /* Protocols in which a specific table may be specified in flow_mods. */
 #define OFPUTIL_P_TID (OFPUTIL_P_OF10_STD_TID | \
                        OFPUTIL_P_OF10_NXM_TID | \
-                       OFPUTIL_P_OF12_OXM)
+                       OFPUTIL_P_OF12_OXM | \
+                       OFPUTIL_P_OF13_OXM)
 };
 
 /* Protocols to use for flow dumps, from most to least preferred. */
@@ -130,7 +132,7 @@ void ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap);
 
 /* Bitmap of OpenFlow versions that Open vSwitch supports. */
 #define OFPUTIL_SUPPORTED_VERSIONS \
-        ((1u << OFP10_VERSION) | (1u << OFP12_VERSION))
+    ((1u << OFP10_VERSION) | (1u << OFP12_VERSION) | (1u << OFP13_VERSION))
 
 /* Bitmap of OpenFlow versions to enable by default (a subset of
  * OFPUTIL_SUPPORTED_VERSIONS). */
@@ -263,6 +265,7 @@ struct ofputil_flow_stats {
     uint64_t byte_count;        /* Byte count, UINT64_MAX if unknown. */
     struct ofpact *ofpacts;
     size_t ofpacts_len;
+    uint16_t flags;             /* Added for OF 1.3 */
 };
 
 int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *,
@@ -399,7 +402,7 @@ struct ofputil_phy_port {
 };
 
 enum ofputil_capabilities {
-    /* OpenFlow 1.0, 1.1 and 1.2 share these values for these capabilities. */
+    /* OpenFlow 1.0, 1.1, 1.2, and 1.3 share these capability values. */
     OFPUTIL_C_FLOW_STATS     = 1 << 0,  /* Flow statistics. */
     OFPUTIL_C_TABLE_STATS    = 1 << 1,  /* Table statistics. */
     OFPUTIL_C_PORT_STATS     = 1 << 2,  /* Port statistics. */
@@ -412,10 +415,10 @@ enum ofputil_capabilities {
     /* OpenFlow 1.0 only. */
     OFPUTIL_C_STP            = 1 << 3,  /* 802.1d spanning tree. */
 
-    /* OpenFlow 1.1 and 1.2 share this capability. */
+    /* OpenFlow 1.1, 1.2, and 1.3 share this capability. */
     OFPUTIL_C_GROUP_STATS    = 1 << 4,  /* Group statistics. */
 
-    /* OpenFlow 1.2 only */
+    /* OpenFlow 1.2 and 1.3 share this capability */
     OFPUTIL_C_PORT_BLOCKED   = 1 << 8,  /* Switch will block looping ports */
 };
 
@@ -455,6 +458,7 @@ struct ofputil_switch_features {
     uint64_t datapath_id;       /* Datapath unique ID. */
     uint32_t n_buffers;         /* Max packets buffered at once. */
     uint8_t n_tables;           /* Number of tables supported by datapath. */
+    uint8_t auxiliary_id;       /* Identify auxiliary connections */
     enum ofputil_capabilities capabilities;
     enum ofputil_action_bitmap actions;
 };
diff --git a/lib/rconn.c b/lib/rconn.c
index a6b634b..45a0acd 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1123,6 +1123,24 @@ is_admitted_msg(const struct ofpbuf *b)
     case OFPTYPE_GET_CONFIG_REQUEST:
     case OFPTYPE_GET_CONFIG_REPLY:
     case OFPTYPE_SET_CONFIG:
+        /* FIXME: Change the following once they are implemented: */
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_GET_ASYNC_REPLY:
+    case OFPTYPE_METER_MOD:
+    case OFPTYPE_GROUP_REQUEST:
+    case OFPTYPE_GROUP_REPLY:
+    case OFPTYPE_GROUP_DESC_REQUEST:
+    case OFPTYPE_GROUP_DESC_REPLY:
+    case OFPTYPE_GROUP_FEATURES_REQUEST:
+    case OFPTYPE_GROUP_FEATURES_REPLY:
+    case OFPTYPE_METER_REQUEST:
+    case OFPTYPE_METER_REPLY:
+    case OFPTYPE_METER_CONFIG_REQUEST:
+    case OFPTYPE_METER_CONFIG_REPLY:
+    case OFPTYPE_METER_FEATURES_REQUEST:
+    case OFPTYPE_METER_FEATURES_REPLY:
+    case OFPTYPE_TABLE_FEATURES_REQUEST:
+    case OFPTYPE_TABLE_FEATURES_REPLY:
         return false;
 
     case OFPTYPE_PACKET_IN:
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 0992fe4..bc3eb54 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2238,7 +2238,8 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
     if (arp_match_ip) {
         features.capabilities |= OFPUTIL_C_ARP_MATCH_IP;
     }
-
+    /* FIXME: Fill in proper features.auxiliary_id for auxiliary connections */
+    features.auxiliary_id = 0;
     b = ofputil_encode_switch_features(&features, ofconn_get_protocol(ofconn),
                                        oh->xid);
     HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
@@ -2261,7 +2262,9 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
     buf = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY, oh, 0);
     osc = ofpbuf_put_uninit(buf, sizeof *osc);
     flags = ofproto->frag_handling;
-    if (ofconn_get_invalid_ttl_to_controller(ofconn)) {
+    /* OFPC_INVALID_TTL_TO_CONTROLLER is deprecated in OF 1.3 */
+    if (oh->version < OFP13_VERSION
+        && ofconn_get_invalid_ttl_to_controller(ofconn)) {
         flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
     }
     osc->flags = htons(flags);
@@ -2294,8 +2297,10 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
             }
         }
     }
+    /* OFPC_INVALID_TTL_TO_CONTROLLER is deprecated in OF 1.3 */
     ofconn_set_invalid_ttl_to_controller(ofconn,
-             (flags & OFPC_INVALID_TTL_TO_CONTROLLER));
+             (oh->version < OFP13_VERSION
+              && flags & OFPC_INVALID_TTL_TO_CONTROLLER));
 
     ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len));
 
@@ -2808,6 +2813,12 @@ handle_flow_stats_request(struct ofconn *ofconn,
                                                &fs.byte_count);
         fs.ofpacts = rule->ofpacts;
         fs.ofpacts_len = rule->ofpacts_len;
+        fs.flags = 0;
+        if (rule->send_flow_removed) {
+            fs.flags |= OFPFF_SEND_FLOW_REM;
+            /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
+               and OFPFF13_NO_BYT_COUNTS */
+        }
         ofputil_append_flow_stats_reply(&fs, &replies);
     }
     ofconn_send_replies(ofconn, &replies);
@@ -3174,6 +3185,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
         return OFPERR_OFPFMFC_OVERLAP;
     }
 
+    /* FIXME: Implement OFPFF12_RESET_COUNTS */
+
     rule->ofproto = ofproto;
     rule->pending = NULL;
     rule->flow_cookie = fm->new_cookie;
@@ -3182,6 +3195,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     rule->hard_timeout = fm->hard_timeout;
     rule->table_id = table - ofproto->tables;
     rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
+    /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
+       and OFPFF13_NO_BYT_COUNTS */
     rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
     rule->ofpacts_len = fm->ofpacts_len;
     rule->evictable = true;
@@ -3267,6 +3282,8 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
         bool actions_changed;
         ovs_be64 new_cookie;
 
+        /* FIXME: Implement OFPFF12_RESET_COUNTS */
+
         if (rule_is_modifiable(rule)) {
             /* At least one rule is modifiable, don't report EPERM error. */
             error = 0;
@@ -3516,17 +3533,6 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
     error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
                                     &ofpacts);
-    if (error) {
-        goto exit_free_ofpacts;
-    }
-
-    if (fm.flags & OFPFF10_EMERG) {
-        /* We do not support the OpenFlow 1.0 emergency flow cache, which
-         * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
-         * There is no good error code, so just state that the flow table
-         * is full. */
-        error = OFPERR_OFPFMFC_TABLE_FULL;
-    }
     if (!error) {
         error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
                               &fm.match.flow, ofproto->max_ports);
@@ -3537,7 +3543,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     if (error) {
         goto exit_free_ofpacts;
     }
-
+    
     /* Record the operation for logging a summary report. */
     switch (fm.command) {
     case OFPFC_ADD:
@@ -4095,6 +4101,18 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
         return handle_flow_monitor_request(ofconn, oh);
 
+        /* FIXME: Change the following once they are implemented: */
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_METER_MOD:
+    case OFPTYPE_GROUP_REQUEST:
+    case OFPTYPE_GROUP_DESC_REQUEST:
+    case OFPTYPE_GROUP_FEATURES_REQUEST:
+    case OFPTYPE_METER_REQUEST:
+    case OFPTYPE_METER_CONFIG_REQUEST:
+    case OFPTYPE_METER_FEATURES_REQUEST:
+    case OFPTYPE_TABLE_FEATURES_REQUEST:
+        return OFPERR_OFPBRC_BAD_TYPE;
+
     case OFPTYPE_HELLO:
     case OFPTYPE_ERROR:
     case OFPTYPE_FEATURES_REPLY:
@@ -4114,6 +4132,14 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_FLOW_MONITOR_PAUSED:
     case OFPTYPE_FLOW_MONITOR_RESUMED:
     case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+    case OFPTYPE_GET_ASYNC_REPLY:
+    case OFPTYPE_GROUP_REPLY:
+    case OFPTYPE_GROUP_DESC_REPLY:
+    case OFPTYPE_GROUP_FEATURES_REPLY:
+    case OFPTYPE_METER_REPLY:
+    case OFPTYPE_METER_CONFIG_REPLY:
+    case OFPTYPE_METER_FEATURES_REPLY:
+    case OFPTYPE_TABLE_FEATURES_REPLY:
     default:
         return OFPERR_OFPBRC_BAD_TYPE;
     }
diff --git a/tests/learn.at b/tests/learn.at
index 2fc82f1..d60b0d3 100644
--- a/tests/learn.at
+++ b/tests/learn.at
@@ -24,7 +24,7 @@ table=0 actions=learn(table=1,hard_timeout=10, NXM_OF_VLAN_TCI[0..11],output:NXM
 table=1 priority=0 actions=flood
 ]])
 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
-[[usable protocols: OpenFlow10+table_id,NXM+table_id,OXM
+[[usable protocols: OpenFlow10+table_id,NXM+table_id,OXM,OpenFlow13
 chosen protocol: OpenFlow10+table_id
 OFPT_FLOW_MOD (xid=0x1): ADD table:255 actions=learn(table=1,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
 OFPT_FLOW_MOD (xid=0x2): ADD table:255 actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
diff --git a/tests/ofp-errors.at b/tests/ofp-errors.at
index b45a33a..9ed33e5 100644
--- a/tests/ofp-errors.at
+++ b/tests/ofp-errors.at
@@ -90,11 +90,13 @@ AT_CHECK([ovs-ofctl print-error OFPBIC_BAD_EXPERIMENTER], [0], [dnl
 OpenFlow 1.0: -1,-1
 OpenFlow 1.1: 3,5
 OpenFlow 1.2: 3,5
+OpenFlow 1.3: 3,5
 ])
 AT_CHECK([ovs-ofctl print-error OFPBIC_BAD_EXP_TYPE], [0], [dnl
 OpenFlow 1.0: -1,-1
 OpenFlow 1.1: 3,5
 OpenFlow 1.2: 3,6
+OpenFlow 1.3: 3,6
 ])
 AT_CLEANUP
 
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 7869a86..7b35f36 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -275,7 +275,7 @@ AT_SETUP([OFPT_FEATURES_REPLY - OF1.1])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 02 06 00 a0 00 00 00 01 00 00 50 54 00 00 00 01 \
-00 00 01 00 02 00 00 00 00 00 00 87 00 00 ff ff \
+00 00 01 00 02 00 00 00 00 00 00 87 00 00 00 00 \
 ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 62 72 30 00 00 00 00 00 00 00 00 00 00 00 00 00 \
 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
@@ -306,7 +306,7 @@ AT_SETUP([OFPT_FEATURES_REPLY cut off mid-port - OF1.1])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 02 06 00 90 00 00 00 01 00 00 50 54 00 00 00 01 \
-00 00 01 00 02 00 00 00 00 00 00 87 00 00 ff ff \
+00 00 01 00 02 00 00 00 00 00 00 87 00 00 00 00 \
 ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 62 72 30 00 00 00 00 00 00 00 00 00 00 00 00 00 \
 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
@@ -317,7 +317,7 @@ ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 "], [0], [dnl
 ***decode error: OFPBRC_BAD_LEN***
 00000000  02 06 00 90 00 00 00 01-00 00 50 54 00 00 00 01 |..........PT....|
-00000010  00 00 01 00 02 00 00 00-00 00 00 87 00 00 ff ff |................|
+00000010  00 00 01 00 02 00 00 00-00 00 00 87 00 00 00 00 |................|
 00000020  ff ff ff fe 00 00 00 00-50 54 00 00 00 01 00 00 |........PT......|
 00000030  62 72 30 00 00 00 00 00-00 00 00 00 00 00 00 00 |br0.............|
 00000040  00 00 00 01 00 00 00 01-00 00 00 00 00 00 00 00 |................|
@@ -335,7 +335,7 @@ AT_SETUP([OFPT_FEATURES_REPLY - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 03 06 00 a0 00 00 00 01 00 00 50 54 00 00 00 01 \
-00 00 01 00 ff 00 00 00 00 00 01 77 00 00 06 ff \
+00 00 01 00 ff 00 00 00 00 00 01 77 00 00 00 00 \
 ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 62 72 30 0a 00 00 00 00 00 00 00 00 00 00 00 00 \
 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
@@ -366,7 +366,7 @@ AT_SETUP([OFPT_FEATURES_REPLY cut off mid-port - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 03 06 00 a0 00 00 00 01 00 00 50 54 00 00 00 01 \
-00 00 01 00 ff 00 00 00 00 00 01 77 00 00 06 ff \
+00 00 01 00 ff 00 00 00 00 00 01 77 00 00 00 00 \
 ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 62 72 30 0a 00 00 00 00 00 00 00 00 00 00 00 00 \
 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
@@ -378,7 +378,7 @@ ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
 OFPT_FEATURES_REPLY (OF1.2) (xid=0x1):
 (***truncated to 144 bytes from 160***)
 00000000  03 06 00 a0 00 00 00 01-00 00 50 54 00 00 00 01 |..........PT....|
-00000010  00 00 01 00 ff 00 00 00-00 00 01 77 00 00 06 ff |...........w....|
+00000010  00 00 01 00 ff 00 00 00-00 00 01 77 00 00 00 00 |...........w....|
 00000020  ff ff ff fe 00 00 00 00-50 54 00 00 00 01 00 00 |........PT......|
 00000030  62 72 30 0a 00 00 00 00-00 00 00 00 00 00 00 00 |br0.............|
 00000040  00 00 00 01 00 00 00 01-00 00 00 00 00 00 00 00 |................|
@@ -391,6 +391,30 @@ AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_FEATURES_REPLY - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 06 00 20 00 00 00 01 00 00 50 54 00 00 00 01 \
+00 00 01 00 ff 00 00 00 00 00 01 77 00 00 00 00 \
+"], [0], [dnl
+OFPT_FEATURES_REPLY (OF1.3) (xid=0x1): dpid:0000505400000001
+n_tables:255, n_buffers:256
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS IP_REASM QUEUE_STATS PORT_BLOCKED
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FEATURES_REPLY - with auxiliary_id - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 06 00 20 00 00 00 01 00 00 50 54 00 00 00 01 \
+00 00 01 00 ff 01 00 00 00 00 01 77 00 00 00 00 \
+"], [0], [dnl
+OFPT_FEATURES_REPLY (OF1.3) (xid=0x1): dpid:0000505400000001
+n_tables:255, n_buffers:256, auxiliary_id:1
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS IP_REASM QUEUE_STATS PORT_BLOCKED
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_GET_CONFIG_REQUEST])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print '0107000800000001'], [0], [dnl
@@ -441,6 +465,21 @@ priority=0,rarp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_PACKET_IN - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 0a 00 54 00 00 00 00 ff ff ff 00 00 2a 00 00 \
+01 02 03 04 05 06 07 08 00 01 00 0c 80 00 00 04 \
+ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \
+00 23 20 83 c1 5f 80 35 00 01 08 00 06 04 00 03 \
+00 23 20 83 c1 5f 00 00 00 00 00 23 20 83 c1 5f \
+00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
+priority=0,rarp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_FLOW_REMOVED - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -466,6 +505,17 @@ OFPT_FLOW_REMOVED (OF1.2) (xid=0x0): dl_vlan=9 reason=hard table_id=5 cookie:0xf
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_FLOW_REMOVED - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 0b 00 40 00 00 00 00 fe dc ba 98 76 54 32 10 \
+80 00 01 05 00 00 00 01 00 98 96 80 00 3c 00 78 \
+00 00 00 00 00 12 d6 87 00 00 00 00 6f 68 ba 66 \
+00 01 00 0a 80 00 0c 02 10 09 00 00 00 00 00 00"], [0], [dnl
+OFPT_FLOW_REMOVED (OF1.3) (xid=0x0): dl_vlan=9 reason=hard table_id=5 cookie:0xfedcba9876543210 duration1.01s idle60 hard120 pkts1234567 bytes1869134438
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_PORT_STATUS - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -603,6 +653,25 @@ OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan
 ])
 AT_CLEANUP
 
+# The flow is formatted with cls_rule_format() for the low-verbosity case.
+AT_SETUP([OFPT_FLOW_MOD - OF1.3 - flags - low verbosity])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
+04 0e 00 90 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 ff 00 00 00 00 00 ff ff \
+ff ff ff ff ff ff ff ff ff ff ff ff 00 1f 00 00 \
+00 01 00 42 80 00 00 04 00 00 00 01 80 00 08 06 \
+50 54 00 00 00 06 80 00 06 06 50 54 00 00 00 05 \
+80 00 0a 02 08 06 80 00 0c 02 00 00 80 00 2a 02 \
+00 02 80 00 2c 04 c0 a8 00 02 80 00 2e 04 c0 a8 \
+00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
+00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
+" 2], [0], [dnl
+OFPT_FLOW_MOD (OF1.3) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 send_flow_rem check_overlap reset_counts no_packet_counts no_byte_counts actions=output:3
+], [dnl
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_FLOW_MOD - OF1.2 - set-field ip_src])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
@@ -708,6 +777,20 @@ OFPT_PORT_MOD (OF1.2) (xid=0x3):port: 3: addr:50:54:00:00:00:01
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_PORT_MOD - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 10 00 28 00 00 00 03 00 00 00 03 00 00 00 00 \
+50 54 00 00 00 01 00 00 00 00 00 01 00 00 00 01 \
+00 00 00 00 00 00 00 00 \
+" 3], [0], [dnl
+OFPT_PORT_MOD (OF1.3) (xid=0x3):port: 3: addr:50:54:00:00:00:01
+     config: PORT_DOWN
+     mask:   PORT_DOWN
+     advertise: UNCHANGED
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_DESC request])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100000000"], [0], [dnl
@@ -819,6 +902,18 @@ OFPST_FLOW request (OF1.2) (xid=0x2): @&t@
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_FLOW request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 12 00 38 00 00 00 02 00 01 00 00 00 00 00 00 \
+ff 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW request (OF1.3) (xid=0x2): @&t@
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_FLOW reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -922,6 +1017,18 @@ OFPST_AGGREGATE request (OF1.2) (xid=0x2): @&t@
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_AGGREGATE request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 12 00 38 00 00 00 02 00 02 00 00 00 00 00 00 \
+ff 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+OFPST_AGGREGATE request (OF1.3) (xid=0x2): @&t@
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_AGGREGATE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -944,6 +1051,17 @@ OFPST_AGGREGATE reply (OF1.2) (xid=0x2): packet_count=121 byte_count=19279 flow_
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_AGGREGATE reply - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 00 28 00 00 00 02 00 02 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 79 00 00 00 00 00 00 4b 4f \
+00 00 00 03 00 00 00 00 \
+"], [0], [dnl
+OFPST_AGGREGATE reply (OF1.3) (xid=0x2): packet_count=121 byte_count=19279 flow_count=3
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_TABLE request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100030000"], [0], [dnl
@@ -965,6 +1083,13 @@ OFPST_TABLE request (OF1.2) (xid=0x2):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_TABLE request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "04120010000000020003000000000000"], [0], [dnl
+OFPST_TABLE request (OF1.3) (xid=0x2):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_TABLE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1035,6 +1160,20 @@ AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "$(cat in)"], [0], [expout])
 AT_CLEANUP
 
+AT_SETUP([OFPST_TABLE reply - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 00 40 00 00 00 01 00 03 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 0b 00 00 00 00 00 00 02 00 \
+00 00 00 00 00 00 01 00 01 00 00 00 00 00 00 0c \
+00 00 00 00 00 00 02 01 00 00 00 00 00 00 01 01 \
+"], [0], [dnl
+OFPST_TABLE reply (OF1.3) (xid=0x1): 2 tables
+  0: active=11, lookup=512, matched=256
+  1: active=12, lookup=513, matched=257
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_PORT request - 1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1065,6 +1204,16 @@ OFPST_PORT request (OF1.2) (xid=0x2): port_no=65535
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_PORT request - 1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 12 00 18 00 00 00 02 00 04 00 00 00 00 00 00 \
+ff ff ff ff 00 00 00 00 \
+"], [0], [dnl
+OFPST_PORT request (OF1.3) (xid=0x2): port_no=65535
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_PORT reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1173,6 +1322,16 @@ OFPST_QUEUE request (OF1.2) (xid=0x2):port=ANY queue=ALL
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_QUEUE request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 12 00 18 00 00 00 02 00 05 00 00 00 00 00 00 \
+ff ff ff ff ff ff ff ff \
+"], [0], [dnl
+OFPST_QUEUE request (OF1.3) (xid=0x2):port=ANY queue=ALL
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_QUEUE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1301,6 +1460,13 @@ OFPT_BARRIER_REQUEST (OF1.2) (xid=0x1):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_BARRIER_REQUEST - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print '04 14 00 08 00 00 00 01'], [0], [dnl
+OFPT_BARRIER_REQUEST (OF1.3) (xid=0x1):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_BARRIER_REPLY - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print '01 13 00 08 00 00 00 01'], [0], [dnl
@@ -1308,20 +1474,47 @@ OFPT_BARRIER_REPLY (xid=0x1):
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_BARRIER_REPLY] - OF1.1)
+AT_SETUP([OFPT_BARRIER_REPLY - OF1.1])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print '02 15 00 08 00 00 00 01'], [0], [dnl
 OFPT_BARRIER_REPLY (OF1.1) (xid=0x1):
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_BARRIER_REPLY] - OF1.2)
+AT_SETUP([OFPT_BARRIER_REPLY - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print '03 15 00 08 00 00 00 01'], [0], [dnl
 OFPT_BARRIER_REPLY (OF1.2) (xid=0x1):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_BARRIER_REPLY - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print '04 15 00 08 00 00 00 01'], [0], [dnl
+OFPT_BARRIER_REPLY (OF1.3) (xid=0x1):
+])
+AT_CLEANUP
+
+
+AT_SETUP([OFPT_SET_ASYNC - OF1.3])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 1c 00 20 00 00 00 00 00 00 10 05 00 00 10 07 \
+00 00 00 03 00 00 00 07 00 00 00 00 00 00 00 03 \
+"], [0], [dnl
+OFPT_SET_ASYNC (OF1.3) (xid=0x0):
+ master:
+       PACKET_IN: no_match invalid_ttl 12
+     PORT_STATUS: add delete
+    FLOW_REMOVED: (off)
+
+ slave:
+       PACKET_IN: no_match action invalid_ttl 12
+     PORT_STATUS: add delete modify
+    FLOW_REMOVED: idle hard
+])
+AT_CLEANUP
+
 AT_SETUP([NXT_ROLE_REQUEST])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
diff --git a/tests/ofp-util.at b/tests/ofp-util.at
index e6dbfcf..fbb6848 100644
--- a/tests/ofp-util.at
+++ b/tests/ofp-util.at
@@ -19,9 +19,14 @@ OFPT_HELLO (OF1.2) (xid=0x1):
 ])
 AT_CHECK([ovs-ofctl encode-hello 0x1e], [0], [dnl
 00000000  04 00 00 08 00 00 00 01-
-OFPT_HELLO (OF 0x04) (xid=0x1):
+OFPT_HELLO (OF1.3) (xid=0x1):
  version bitmap: 0x01, 0x02, 0x03, 0x04
 ])
+AT_CHECK([ovs-ofctl encode-hello 0x3e], [0], [dnl
+00000000  05 00 00 08 00 00 00 01-
+OFPT_HELLO (OF 0x05) (xid=0x1):
+ version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05
+])
 
 dnl Some versions below max version missing.
 AT_CHECK([ovs-ofctl encode-hello 0xc], [0], [dnl




More information about the dev mailing list