[ovs-dev] [packet_in v2 18/18] openflow: New Nicira Extended PACKET_IN format.

Ethan Jackson ethan at nicira.com
Sat Jan 7 19:11:59 UTC 2012


The new PACKET_IN format implemented in this patch includes flow
metadata such as the cookie, table_id, and registers.

Signed-off-by: Ethan Jackson <ethan at nicira.com>
---
 include/openflow/nicira-ext.h |   68 ++++++++++++++++-
 lib/learning-switch.c         |    2 +
 lib/ofp-print.c               |   27 +++++++
 lib/ofp-util.c                |  168 ++++++++++++++++++++++++++++++++++++----
 lib/ofp-util.h                |   15 ++++-
 ofproto/connmgr.c             |   24 ++++++-
 ofproto/connmgr.h             |    3 +
 ofproto/ofproto-dpif.c        |   40 ++++++++--
 ofproto/ofproto.c             |   27 +++++++
 tests/ofproto-dpif.at         |   72 +++++++++---------
 utilities/ovs-ofctl.8.in      |   20 +++++
 utilities/ovs-ofctl.c         |   30 +++++++
 12 files changed, 431 insertions(+), 65 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 1dcd32b..8933dcb 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -162,7 +162,11 @@ enum nicira_type {
     /* Use the upper 8 bits of the 'command' member in struct ofp_flow_mod to
      * designate the table to which a flow is to be added?  See the big comment
      * on struct nxt_flow_mod_table_id for more information. */
-    NXT_FLOW_MOD_TABLE_ID = 15
+    NXT_FLOW_MOD_TABLE_ID = 15,
+
+    /* Alternative PACKET_IN message formats. */
+    NXT_SET_PACKET_IN_FORMAT = 16, /* Set Packet In format. */
+    NXT_PACKET_IN = 17             /* Nicira Packet In. */
 };
 
 /* Header for Nicira vendor stats request and reply messages. */
@@ -246,6 +250,68 @@ struct nxt_flow_mod_table_id {
 };
 OFP_ASSERT(sizeof(struct nxt_flow_mod_table_id) == 24);
 
+enum nx_packet_in_format {
+    NXPIF_OPENFLOW10 = 0,       /* Standard OpenFlow 1.0 compatible. */
+    NXPIF_NXM = 1               /* Nicira Extended. */
+};
+
+/* NXT_SET_PACKET_IN_FORMAT request. */
+struct nxt_set_packet_in_format {
+    struct nicira_header nxh;
+    ovs_be32 format;            /* One of NXPIF_*. */
+    uint8_t pad[4];
+};
+OFP_ASSERT(sizeof(struct nxt_set_packet_in_format) == 24);
+
+/* NXT_PACKET_IN (analogous to OFPT_PACKET_IN).
+ *
+ * The NXT_PACKET_IN format is intended to model the OpenFLow-1.2 PACKET_IN
+ * with some minor tweaks.  Most notably NXT_PACKET_IN includes the cookie of
+ * the rule which triggered the NXT_PACKET_IN message, and the match fields are
+ * in NXM format.
+ *
+ * The match fields in the NXT_PACKET_IN are intended to contain flow
+ * processing metadata collected at the time the NXT_PACKET_IN message was
+ * triggered.  It is minimally required to contain the NXM_OF_IN_PORT of the
+ * packet, but may include other NXM headers such as flow registers.  The match
+ * fields are allowed to contain non-metadata (e.g. NXM_OF_ETH_SRC etc).
+ * However, this information can typically be found in the packet directly, so
+ * it may be redundant.
+ *
+ * Whereas in most cases a controller can expect to only get back NXM fields
+ * that it set up itself (e.g. flow dumps will ordinarily report only NXM
+ * fields from flows that the controller added), NXT_PACKET_IN messages might
+ * contain fields that the controller does not understand, because the switch
+ * might support fields (new registers, new protocols, etc.) that the
+ * controller does not.  The controller must prepared to tolerate these.
+ *
+ * The 'cookie' and 'table_id' fields have no meaning when 'reason' is
+ * OFPR_NO_MATCH.  In this case they should be set to 0. */
+struct nxt_packet_in {
+    struct nicira_header nxh;
+    ovs_be32 buffer_id;       /* ID assigned by datapath. */
+    ovs_be16 total_len;       /* Full length of frame. */
+    uint8_t reason;           /* Reason packet is sent (one of OFPR_*). */
+    uint8_t table_id;         /* ID of the table that was looked up. */
+    ovs_be64 cookie;          /* Cookie of the rule that was looked up. */
+    ovs_be16 match_len;       /* Size of nx_match. */
+    uint8_t pad[6];           /* Align to 64-bits. */
+    /* Followed by:
+     *   - Exactly match_len (possibly 0) bytes containing the nx_match, then
+     *   - Exactly (match_len + 7)/8*8 - match_len (between 0 and 7) bytes of
+     *     all-zero bytes, then
+     *   - Exactly 2 all-zero padding bytes, then
+     *   - An Ethernet frame whose length is inferred from nxh.header.length.
+     *
+     * The padding bytes preceding the Ethernet frame ensure that the IP
+     * header (if any) following the Ethernet header is 32-bit aligned. */
+
+    /* uint8_t nxm_fields[...]; */ /* Match. */
+    /* uint8_t pad[2]; */          /* Align to 64 bit + 16 bit. */
+    /* uint8_t data[0]; */         /* Ethernet frame. */
+};
+OFP_ASSERT(sizeof(struct nxt_packet_in) == 40);
+
 /* Configures the "role" of the sending controller.  The default role is:
  *
  *    - Other (NX_ROLE_OTHER), which allows the controller access to all
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index ecc5509..2fc6392 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -257,6 +257,8 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
     case OFPUTIL_NXT_ROLE_REPLY:
     case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
     case OFPUTIL_NXT_SET_FLOW_FORMAT:
+    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+    case OFPUTIL_NXT_PACKET_IN:
     case OFPUTIL_NXT_FLOW_MOD:
     case OFPUTIL_NXT_FLOW_REMOVED:
     case OFPUTIL_NXST_FLOW_REQUEST:
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 0f05fae..9c88daf 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -92,6 +92,14 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
         return;
     }
 
+    if (pin.table_id) {
+        ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
+    }
+
+    if (pin.cookie) {
+        ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
+    }
+
     ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
     ofputil_format_port(pin.fmd.in_port, string);
 
@@ -1265,6 +1273,20 @@ ofp_print_nxt_set_flow_format(struct ds *string,
 }
 
 static void
+ofp_print_nxt_set_packet_in_format(struct ds *string,
+                                   const struct nxt_set_packet_in_format *nspf)
+{
+    uint32_t format = ntohl(nspf->format);
+
+    ds_put_cstr(string, " format=");
+    if (ofputil_packet_in_format_is_valid(format)) {
+        ds_put_cstr(string, ofputil_packet_in_format_to_string(format));
+    } else {
+        ds_put_format(string, "%"PRIu32, format);
+    }
+}
+
+static void
 ofp_to_string__(const struct ofp_header *oh,
                 const struct ofputil_msg_type *type, struct ds *string,
                 int verbosity)
@@ -1311,6 +1333,7 @@ ofp_to_string__(const struct ofp_header *oh,
         break;
 
     case OFPUTIL_OFPT_PACKET_IN:
+    case OFPUTIL_NXT_PACKET_IN:
         ofp_print_packet_in(string, msg, verbosity);
         break;
 
@@ -1414,6 +1437,10 @@ ofp_to_string__(const struct ofp_header *oh,
         ofp_print_nxt_set_flow_format(string, msg);
         break;
 
+    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+        ofp_print_nxt_set_packet_in_format(string, msg);
+        break;
+
     case OFPUTIL_NXT_FLOW_MOD:
         ofp_print_flow_mod(string, msg, code, verbosity);
         break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 842a843..3cd09dc 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -363,6 +363,14 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
           NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
           sizeof(struct nxt_set_flow_format), 0 },
 
+        { OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
+          NXT_SET_PACKET_IN_FORMAT, "NXT_SET_PACKET_IN_FORMAT",
+          sizeof(struct nxt_set_packet_in_format), 0 },
+
+        { OFPUTIL_NXT_PACKET_IN,
+          NXT_PACKET_IN, "NXT_PACKET_IN",
+          sizeof(struct nxt_packet_in), 1 },
+
         { OFPUTIL_NXT_FLOW_MOD,
           NXT_FLOW_MOD, "NXT_FLOW_MOD",
           sizeof(struct nx_flow_mod), 8 },
@@ -839,6 +847,39 @@ ofputil_flow_format_from_string(const char *s)
             : -1);
 }
 
+bool
+ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format)
+{
+    switch (packet_in_format) {
+    case NXPIF_OPENFLOW10:
+    case NXPIF_NXM:
+        return true;
+    }
+
+    return false;
+}
+
+const char *
+ofputil_packet_in_format_to_string(enum nx_packet_in_format packet_in_format)
+{
+    switch (packet_in_format) {
+    case NXPIF_OPENFLOW10:
+        return "openflow10";
+    case NXPIF_NXM:
+        return "nxm";
+    default:
+        NOT_REACHED();
+    }
+}
+
+int
+ofputil_packet_in_format_from_string(const char *s)
+{
+    return (!strcmp(s, "openflow10") ? NXPIF_OPENFLOW10
+            : !strcmp(s, "nxm") ? NXPIF_NXM
+            : -1);
+}
+
 static bool
 regs_fully_wildcarded(const struct flow_wildcards *wc)
 {
@@ -927,6 +968,18 @@ ofputil_make_set_flow_format(enum nx_flow_format flow_format)
     return msg;
 }
 
+struct ofpbuf *
+ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format)
+{
+    struct nxt_set_packet_in_format *spif;
+    struct ofpbuf *msg;
+
+    spif = make_nxmsg(sizeof *spif, NXT_SET_PACKET_IN_FORMAT, &msg);
+    spif->format = htonl(packet_in_format);
+
+    return msg;
+}
+
 /* Returns an OpenFlow message that can be used to turn the flow_mod_table_id
  * extension on or off (according to 'flow_mod_table_id'). */
 struct ofpbuf *
@@ -1565,6 +1618,39 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
         pin->reason = opi->reason;
         pin->buffer_id = ntohl(opi->buffer_id);
         pin->total_len = ntohs(opi->total_len);
+    } else if (code == OFPUTIL_NXT_PACKET_IN) {
+        const struct nxt_packet_in *npi;
+        struct cls_rule rule;
+        struct ofpbuf b;
+        int error;
+
+        ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+        npi = ofpbuf_pull(&b, sizeof *npi);
+        error = nx_pull_match(&b, ntohs(npi->match_len), false, 0, &rule, NULL,
+                              NULL);
+        if (error) {
+            return error;
+        }
+        ofpbuf_pull(&b, 2);
+
+        pin->packet = b.data;
+        pin->packet_len = b.size;
+        pin->reason = npi->reason;
+        pin->table_id = npi->table_id;
+        pin->cookie = npi->cookie;
+
+        pin->fmd.in_port = rule.flow.in_port;
+
+        pin->fmd.tun_id = rule.flow.tun_id;
+        pin->fmd.tun_id_mask = rule.wc.tun_id_mask;
+
+        memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs);
+        memcpy(pin->fmd.reg_masks, rule.wc.reg_masks,
+               sizeof pin->fmd.reg_masks);
+
+        pin->buffer_id = ntohl(npi->buffer_id);
+        pin->total_len = ntohs(npi->total_len);
     } else {
         NOT_REACHED();
     }
@@ -1572,27 +1658,75 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
     return 0;
 }
 
-/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message
- * and returns the message. */
+/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
+ * in the format specified by 'packet_in_format'.  */
 struct ofpbuf *
-ofputil_encode_packet_in(const struct ofputil_packet_in *pin)
+ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
+                         enum nx_packet_in_format packet_in_format)
 {
-    struct ofp_packet_in opi;
-    struct ofpbuf *rw_packet;
-
-    rw_packet = ofpbuf_clone_data_with_headroom(
-        pin->packet, MIN(pin->send_len, pin->packet_len),
-        offsetof(struct ofp_packet_in, data));
+    size_t send_len = MIN(pin->send_len, pin->packet_len);
+    struct ofpbuf *rw_packet = ofpbuf_new(0);
 
     /* Add OFPT_PACKET_IN. */
-    memset(&opi, 0, sizeof opi);
-    opi.header.version = OFP_VERSION;
-    opi.header.type = OFPT_PACKET_IN;
-    opi.total_len = htons(pin->packet_len);
-    opi.in_port = htons(pin->fmd.in_port);
-    opi.reason = pin->reason;
-    opi.buffer_id = htonl(pin->buffer_id);
-    ofpbuf_push(rw_packet, &opi, offsetof(struct ofp_packet_in, data));
+    if (packet_in_format == NXPIF_OPENFLOW10) {
+        size_t header_len = offsetof(struct ofp_packet_in, data);
+        struct ofp_packet_in *opi;
+
+        ofpbuf_prealloc_tailroom(rw_packet, send_len + header_len);
+
+        opi = ofpbuf_put_zeros(rw_packet, header_len);
+        opi->header.version = OFP_VERSION;
+        opi->header.type = OFPT_PACKET_IN;
+        opi->total_len = htons(pin->packet_len);
+        opi->in_port = htons(pin->fmd.in_port);
+        opi->reason = pin->reason;
+        opi->buffer_id = htonl(pin->buffer_id);
+
+        ofpbuf_put(rw_packet, pin->packet, send_len);
+    } else if (packet_in_format == NXPIF_NXM) {
+        struct nxt_packet_in *npi;
+        struct cls_rule rule;
+        size_t match_len;
+        size_t i;
+
+        /* Estimate of required PACKET_IN length includes the NPI header, space
+         * for the match (2 times sizeof the metadata seems like enough), 2
+         * bytes for padding, and the packet length. */
+        ofpbuf_prealloc_tailroom(rw_packet,
+                                 sizeof *npi + sizeof(struct flow_metadata) * 2
+                                 + 2 + send_len);
+
+        cls_rule_init_catchall(&rule, 0);
+        cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
+                                   pin->fmd.tun_id_mask);
+
+        for (i = 0; i < FLOW_N_REGS; i++) {
+            cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i],
+                                    pin->fmd.reg_masks[i]);
+        }
+
+        cls_rule_set_in_port(&rule, pin->fmd.in_port);
+
+        ofpbuf_put_zeros(rw_packet, sizeof *npi);
+        match_len = nx_put_match(rw_packet, &rule, 0, 0);
+        ofpbuf_put_zeros(rw_packet, 2);
+        ofpbuf_put(rw_packet, pin->packet, send_len);
+
+        npi = rw_packet->data;
+        npi->nxh.header.version = OFP_VERSION;
+        npi->nxh.header.type = OFPT_VENDOR;
+        npi->nxh.vendor = htonl(NX_VENDOR_ID);
+        npi->nxh.subtype = htonl(NXT_PACKET_IN);
+
+        npi->buffer_id = htonl(pin->buffer_id);
+        npi->total_len = htons(pin->packet_len);
+        npi->reason = pin->reason;
+        npi->table_id = pin->table_id;
+        npi->cookie = pin->cookie;
+        npi->match_len = htons(match_len);
+    } else {
+        NOT_REACHED();
+    }
     update_openflow_length(rw_packet);
 
     return rw_packet;
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index c3fafba..13195c7 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -77,6 +77,8 @@ enum ofputil_msg_code {
     OFPUTIL_NXT_FLOW_MOD_TABLE_ID,
     OFPUTIL_NXT_FLOW_MOD,
     OFPUTIL_NXT_FLOW_REMOVED,
+    OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
+    OFPUTIL_NXT_PACKET_IN,
 
     /* NXST_* stat requests. */
     OFPUTIL_NXST_FLOW_REQUEST,
@@ -124,6 +126,12 @@ enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *);
 
 struct ofpbuf *ofputil_make_set_flow_format(enum nx_flow_format);
 
+/* PACKET_IN. */
+bool ofputil_packet_in_format_is_valid(enum nx_packet_in_format);
+int ofputil_packet_in_format_from_string(const char *);
+const char *ofputil_packet_in_format_to_string(enum nx_packet_in_format);
+struct ofpbuf *ofputil_make_set_packet_in_format(enum nx_packet_in_format);
+
 /* NXT_FLOW_MOD_TABLE_ID extension. */
 struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id);
 
@@ -218,6 +226,8 @@ struct ofputil_packet_in {
     size_t packet_len;
 
     uint8_t reason;             /* One of OFPR_*. */
+    uint8_t table_id;
+    ovs_be64 cookie;
 
     uint32_t buffer_id;
     int send_len;
@@ -228,7 +238,10 @@ struct ofputil_packet_in {
 
 int ofputil_decode_packet_in(struct ofputil_packet_in *,
                              const struct ofp_header *);
-struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *);
+struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *,
+                                        enum nx_packet_in_format);
+int ofputil_decode_packet_in(struct ofputil_packet_in *pi,
+                             const struct ofp_header *oh);
 
 /* OpenFlow protocol utility functions. */
 void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 33e6592..46d6d79 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -48,6 +48,7 @@ struct ofconn {
     struct rconn *rconn;        /* OpenFlow connection. */
     enum ofconn_type type;      /* Type. */
     enum nx_flow_format flow_format; /* Currently selected flow format. */
+    enum nx_packet_in_format packet_in_format; /* OFPT_PACKET_IN format. */
     bool flow_mod_table_id;     /* NXT_FLOW_MOD_TABLE_ID enabled? */
 
     /* Asynchronous flow table operation support. */
@@ -769,6 +770,25 @@ ofconn_set_flow_format(struct ofconn *ofconn, enum nx_flow_format flow_format)
     ofconn->flow_format = flow_format;
 }
 
+/* Returns the currently configured packet in format for 'ofconn', one of
+ * NXPIF_*.
+ *
+ * The default, if no other format has been set, is NXPIF_OPENFLOW10. */
+enum nx_packet_in_format
+ofconn_get_packet_in_format(struct ofconn *ofconn)
+{
+    return ofconn->packet_in_format;
+}
+
+/* Sets the packet in format for 'ofconn' to 'packet_in_format' (one of
+ * NXPIF_*). */
+void
+ofconn_set_packet_in_format(struct ofconn *ofconn,
+                            enum nx_packet_in_format packet_in_format)
+{
+    ofconn->packet_in_format = packet_in_format;
+}
+
 /* Returns true if the NXT_FLOW_MOD_TABLE_ID extension is enabled, false
  * otherwise.
  *
@@ -906,6 +926,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type)
     ofconn->rconn = rconn;
     ofconn->type = type;
     ofconn->flow_format = NXFF_OPENFLOW10;
+    ofconn->packet_in_format = NXPIF_OPENFLOW10;
     ofconn->flow_mod_table_id = false;
     list_init(&ofconn->opgroups);
     ofconn->role = NX_ROLE_OTHER;
@@ -1212,7 +1233,8 @@ schedule_packet_in(struct ofconn *ofconn, struct ofputil_packet_in pin,
      * immediately call into do_send_packet_in() or it might buffer it for a
      * while (until a later call to pinsched_run()). */
     pinsched_send(ofconn->schedulers[pin.reason == OFPR_NO_MATCH ? 0 : 1],
-                  flow->in_port, ofputil_encode_packet_in(&pin),
+                  flow->in_port,
+                  ofputil_encode_packet_in(&pin, ofconn->packet_in_format),
                   do_send_packet_in, ofconn);
 }
 
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index d8a5e56..0df840b 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -85,6 +85,9 @@ void ofconn_set_role(struct ofconn *, enum nx_role);
 enum nx_flow_format ofconn_get_flow_format(struct ofconn *);
 void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format);
 
+enum nx_packet_in_format ofconn_get_packet_in_format(struct ofconn *);
+void ofconn_set_packet_in_format(struct ofconn *, enum nx_packet_in_format);
+
 bool ofconn_get_flow_mod_table_id(const struct ofconn *);
 void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable);
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 97ddfed..f5280ff 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -214,6 +214,9 @@ struct action_xlate_ctx {
      * we are just revalidating. */
     bool may_learn;
 
+    /* Cookie of the currently matching rule, or 0. */
+    ovs_be64 cookie;
+
     /* If nonnull, called just before executing a resubmit action.
      *
      * This is normally null so the client has to set it manually after
@@ -247,7 +250,8 @@ struct action_xlate_ctx {
 
 static void action_xlate_ctx_init(struct action_xlate_ctx *,
                                   struct ofproto_dpif *, const struct flow *,
-                                  ovs_be16 initial_tci, const struct ofpbuf *);
+                                  ovs_be16 initial_tci, ovs_be64 cookie,
+                                  const struct ofpbuf *);
 static struct ofpbuf *xlate_actions(struct action_xlate_ctx *,
                                     const union ofp_action *in, size_t n_in);
 
@@ -2415,6 +2419,10 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, struct ofpbuf *packet,
     pin.packet_len = packet->size;
     pin.total_len = packet->size;
     pin.reason = OFPR_NO_MATCH;
+
+    pin.table_id = 0;
+    pin.cookie = 0;
+
     pin.buffer_id = 0;          /* not yet known */
     pin.send_len = 0;           /* not used for flow table misses */
 
@@ -3196,7 +3204,8 @@ facet_account(struct ofproto_dpif *ofproto, struct facet *facet)
         struct action_xlate_ctx ctx;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              facet->flow.vlan_tci, NULL);
+                              facet->flow.vlan_tci,
+                              facet->rule->up.flow_cookie, NULL);
         ctx.may_learn = true;
         ofpbuf_delete(xlate_actions(&ctx, facet->rule->up.actions,
                                     facet->rule->up.n_actions));
@@ -3385,7 +3394,8 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
         bool should_install;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, NULL);
+                              subfacet->initial_tci, new_rule->up.flow_cookie,
+                              NULL);
         odp_actions = xlate_actions(&ctx, new_rule->up.actions,
                                     new_rule->up.n_actions);
         actions_changed = (subfacet->actions_len != odp_actions->size
@@ -3535,7 +3545,8 @@ flow_push_stats(const struct rule_dpif *rule,
     push.bytes = bytes;
     push.used = used;
 
-    action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, NULL);
+    action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci,
+                          rule->up.flow_cookie, NULL);
     push.ctx.resubmit_hook = push_resubmit;
     ofpbuf_delete(xlate_actions(&push.ctx,
                                 rule->up.actions, rule->up.n_actions));
@@ -3677,7 +3688,7 @@ subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet,
     struct action_xlate_ctx ctx;
 
     action_xlate_ctx_init(&ctx, p, &facet->flow, subfacet->initial_tci,
-                          packet);
+                          rule->up.flow_cookie, packet);
     odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
     facet->tags = ctx.tags;
     facet->may_install = ctx.may_set_up_flow;
@@ -3955,7 +3966,8 @@ rule_execute(struct rule *rule_, const struct flow *flow,
     struct ofpbuf *odp_actions;
     size_t size;
 
-    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
+    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
+                          rule->up.flow_cookie, packet);
     odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
     size = packet->size;
     if (execute_odp_actions(ofproto, flow, odp_actions->data,
@@ -4225,8 +4237,12 @@ xlate_table_action(struct action_xlate_ctx *ctx,
         }
 
         if (rule) {
+            ovs_be64 old_cookie = ctx->cookie;
+
             ctx->recurse++;
+            ctx->cookie = rule->up.flow_cookie;
             do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx);
+            ctx->cookie = old_cookie;
             ctx->recurse--;
         }
 
@@ -4323,6 +4339,9 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len)
     pin.packet = packet->data;
     pin.packet_len = packet->size;
     pin.reason = OFPR_ACTION;
+    pin.table_id = ctx->table_id;
+    pin.cookie = ctx->cookie;
+
     pin.buffer_id = 0;
     pin.send_len = len;
     pin.total_len = packet->size;
@@ -4728,13 +4747,15 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
 static void
 action_xlate_ctx_init(struct action_xlate_ctx *ctx,
                       struct ofproto_dpif *ofproto, const struct flow *flow,
-                      ovs_be16 initial_tci, const struct ofpbuf *packet)
+                      ovs_be16 initial_tci, ovs_be64 cookie,
+                      const struct ofpbuf *packet)
 {
     ctx->ofproto = ofproto;
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
     ctx->base_flow.tun_id = 0;
     ctx->base_flow.vlan_tci = initial_tci;
+    ctx->cookie = cookie;
     ctx->packet = packet;
     ctx->may_learn = packet != NULL;
     ctx->resubmit_hook = NULL;
@@ -5520,7 +5541,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
         ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
         odp_flow_key_from_flow(&key, flow);
 
-        action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
+        action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, 0, packet);
         odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions);
         dpif_execute(ofproto->dpif, key.data, key.size,
                      odp_actions->data, odp_actions->size, packet);
@@ -5810,7 +5831,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
 
         trace.result = &result;
         trace.flow = flow;
-        action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci, packet);
+        action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci,
+                              rule->up.flow_cookie, packet);
         trace.ctx.resubmit_hook = trace_resubmit;
         odp_actions = xlate_actions(&trace.ctx,
                                     rule->up.actions, rule->up.n_actions);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index af35aba..8f3c158 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2863,6 +2863,29 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
 }
 
 static int
+handle_nxt_set_packet_in_format(struct ofconn *ofconn,
+                                const struct ofp_header *oh)
+{
+    const struct nxt_set_packet_in_format *msg;
+    uint32_t format;
+
+    msg = (const struct nxt_set_packet_in_format *) oh;
+    format = ntohl(msg->format);
+    if (format != NXFF_OPENFLOW10 && format != NXPIF_NXM) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
+    }
+
+    if (format != ofconn_get_packet_in_format(ofconn)
+        && ofconn_has_pending_opgroups(ofconn)) {
+        /* Avoid sending async message in surprsing packet in format. */
+        return OFPROTO_POSTPONE;
+    }
+
+    ofconn_set_packet_in_format(ofconn, format);
+    return 0;
+}
+
+static int
 handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofp_header *ob;
@@ -2929,6 +2952,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPUTIL_NXT_SET_FLOW_FORMAT:
         return handle_nxt_set_flow_format(ofconn, oh);
 
+    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+        return handle_nxt_set_packet_in_format(ofconn, oh);
+
     case OFPUTIL_NXT_FLOW_MOD:
         return handle_flow_mod(ofconn, oh);
 
@@ -2972,6 +2998,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPUTIL_OFPST_AGGREGATE_REPLY:
     case OFPUTIL_NXT_ROLE_REPLY:
     case OFPUTIL_NXT_FLOW_REMOVED:
+    case OFPUTIL_NXT_PACKET_IN:
     case OFPUTIL_NXST_FLOW_REPLY:
     case OFPUTIL_NXST_AGGREGATE_REPLY:
     default:
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index c33f6ac..3a7f47b 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -201,16 +201,16 @@ OVS_VSWITCHD_START([dnl
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_DATA([flows.txt], [dnl
 cookie=0x0 dl_src=10:11:11:11:11:11 actions=controller
-cookie=0x1 dl_src=20:22:22:22:22:22 actions=controller,resubmit:80
+cookie=0x1 dl_src=20:22:22:22:22:22 actions=controller,resubmit(80,1)
 cookie=0x2 dl_src=30:33:33:33:33:33 actions=mod_vlan_vid:15,controller
 
-cookie=0x3 in_port=80 actions=mod_vlan_vid:80,controller,resubmit:81
-cookie=0x4 in_port=81 actions=mod_dl_src:80:81:81:81:81:81,controller,resubmit:82
-cookie=0x5 in_port=82 actions=mod_dl_dst:82:82:82:82:82:82,controller,resubmit:83
-cookie=0x6 in_port=83 actions=mod_nw_src:83.83.83.83,controller,resubmit:84
-cookie=0x7 in_port=84 actions=mod_nw_dst:84.84.84.84,controller,resubmit:85
-cookie=0x8 in_port=85 actions=mod_tp_src:85,controller,resubmit:86
-cookie=0x9 in_port=86 actions=mod_tp_dst:86,controller,controller
+cookie=0x3 table=1 in_port=80 actions=load:1->NXM_NX_REG0[[]],mod_vlan_vid:80,controller,resubmit(81,2)
+cookie=0x4 table=2 in_port=81 actions=load:2->NXM_NX_REG1[[]],mod_dl_src:80:81:81:81:81:81,controller,resubmit(82,3)
+cookie=0x5 table=3 in_port=82 actions=load:3->NXM_NX_REG2[[]],mod_dl_dst:82:82:82:82:82:82,controller,resubmit(83,4)
+cookie=0x6 table=4 in_port=83 actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.83.83,controller,resubmit(84,5)
+cookie=0x7 table=5 in_port=84 actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6)
+cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7)
+cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
@@ -272,7 +272,7 @@ priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) mac(30:33:33:33:33:33->50:54
 ])
 
 dnl Checksum TCP.
-AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log])
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 for i in 1 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=20:22:22:22:22:22,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=11)'
@@ -280,36 +280,36 @@ done
 
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=60 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) tcp_csum:1a03
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) tcp_csum:3205
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) tcp_csum:31b8
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
 ])
 
 dnl Checksum UDP.
-AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> ofctl_monitor.log])
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 for i in 1 ; do
     ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 20 22 22 22 22 22 08 00 45 00 00 1C 00 00 00 00 00 11 00 00 C0 A8 00 01 C0 A8 00 02 00 08 00 0B 00 00 12 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
@@ -317,45 +317,45 @@ done
 
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=60 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) udp_csum:2c37
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) udp_csum:4439
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) udp_csum:43ec
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
 dnl
-OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
 priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
 ])
 
 AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_DURATION | sort], [0], [dnl
  cookie=0x0, duration=?s, table=0, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
- cookie=0x1, duration=?s, table=0, n_packets=2, n_bytes=120, dl_src=20:22:22:22:22:22 actions=CONTROLLER:65535,resubmit:80
+ cookie=0x1, duration=?s, table=0, n_packets=2, n_bytes=120, dl_src=20:22:22:22:22:22 actions=CONTROLLER:65535,resubmit(80,1)
  cookie=0x2, duration=?s, table=0, n_packets=3, n_bytes=180, dl_src=30:33:33:33:33:33 actions=mod_vlan_vid:15,CONTROLLER:65535
- cookie=0x3, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=80 actions=mod_vlan_vid:80,CONTROLLER:65535,resubmit:81
- cookie=0x4, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=81 actions=mod_dl_src:80:81:81:81:81:81,CONTROLLER:65535,resubmit:82
- cookie=0x5, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=82 actions=mod_dl_dst:82:82:82:82:82:82,CONTROLLER:65535,resubmit:83
- cookie=0x6, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=83 actions=mod_nw_src:83.83.83.83,CONTROLLER:65535,resubmit:84
- cookie=0x7, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=84 actions=mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit:85
- cookie=0x8, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit:86
- cookie=0x9, duration=?s, table=0, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
+ cookie=0x3, duration=?s, table=1, n_packets=2, n_bytes=120, in_port=80 actions=load:0x1->NXM_NX_REG0[[]],mod_vlan_vid:80,CONTROLLER:65535,resubmit(81,2)
+ cookie=0x4, duration=?s, table=2, n_packets=2, n_bytes=120, in_port=81 actions=load:0x2->NXM_NX_REG1[[]],mod_dl_src:80:81:81:81:81:81,CONTROLLER:65535,resubmit(82,3)
+ cookie=0x5, duration=?s, table=3, n_packets=2, n_bytes=120, in_port=82 actions=load:0x3->NXM_NX_REG2[[]],mod_dl_dst:82:82:82:82:82:82,CONTROLLER:65535,resubmit(83,4)
+ cookie=0x6, duration=?s, table=4, n_packets=2, n_bytes=120, in_port=83 actions=load:0x4->NXM_NX_REG3[[]],mod_nw_src:83.83.83.83,CONTROLLER:65535,resubmit(84,5)
+ cookie=0x7, duration=?s, table=5, n_packets=2, n_bytes=120, in_port=84 actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6)
+ cookie=0x8, duration=?s, table=6, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7)
+ cookie=0x9, duration=?s, table=7, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
 NXST_FLOW reply (xid=0x4):
 ])
 
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 6c78c68..26a4072 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -1049,6 +1049,26 @@ above table, overrides \fBovs\-ofctl\fR's default choice of flow
 format.  If a command cannot work as requested using the requested
 flow format, \fBovs\-ofctl\fR will report a fatal error.
 .
+.
+.IP "\fB\-P \fIformat\fR"
+.IQ "\fB\-\-packet\-in\-format=\fIformat\fR"
+\fBovs\-ofctl\fR supports the following packet_in formats, in order of
+increasing capability:
+.RS
+.IP "\fBopenflow10\fR"
+This is the standard OpenFlow 1.0 packet in format. It should be supported by
+all OpenFlow switches.
+.
+.IP "\fBnxm\fR (Nicira Extended Match)"
+This packet_in format includes flow metadata encoded using the NXM format.
+.
+.RE
+.IP
+Usually, \fBovs\-ofctl\fR allows the switch to choose its default packet_in
+format.  When \fIformat\fR is one of the formats listed in the above table,
+\fBovs\-ofctl\fR will insist on the selected format.  If the switch does not
+support the requested format, \fBovs\-ofctl\fR will report a fatal error.
+.
 .IP "\fB\-m\fR"
 .IQ "\fB\-\-more\fR"
 Increases the verbosity of OpenFlow messages printed and logged by
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 51dd92f..8b41b03 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -66,6 +66,11 @@ static bool readd;
  * particular flow format or -1 to let ovs-ofctl choose intelligently. */
 static int preferred_flow_format = -1;
 
+/* -P, --packet-in-format: Packet IN format to use in monitor and snoop
+ * commands.  Either one of NXPIF_* to force a particular packet_in format, or
+ * -1 to let ovs-ofctl choose the default. */
+static int preferred_packet_in_format = -1;
+
 /* -m, --more: Additional verbosity for ofp-print functions. */
 static int verbosity;
 
@@ -98,6 +103,7 @@ parse_options(int argc, char *argv[])
         {"strict", no_argument, NULL, OPT_STRICT},
         {"readd", no_argument, NULL, OPT_READD},
         {"flow-format", required_argument, NULL, 'F'},
+        {"packet-in-format", required_argument, NULL, 'P'},
         {"more", no_argument, NULL, 'm'},
         {"help", no_argument, NULL, 'h'},
         {"version", no_argument, NULL, 'V'},
@@ -135,6 +141,14 @@ parse_options(int argc, char *argv[])
             }
             break;
 
+        case 'P':
+            preferred_packet_in_format =
+                ofputil_packet_in_format_from_string(optarg);
+            if (preferred_packet_in_format < 0) {
+                ovs_fatal(0, "unknown packet-in format `%s'", optarg);
+            }
+            break;
+
         case 'm':
             verbosity++;
             break;
@@ -205,6 +219,7 @@ usage(void)
            "  --strict                    use strict match for flow commands\n"
            "  --readd                     replace flows that haven't changed\n"
            "  -F, --flow-format=FORMAT    force particular flow format\n"
+           "  -P, --packet-in-format=FRMT force particular packet in format\n"
            "  -m, --more                  be more verbose printing OpenFlow\n"
            "  -t, --timeout=SECS          give up after SECS seconds\n"
            "  -h, --help                  display this help message\n"
@@ -766,12 +781,27 @@ do_del_flows(int argc, char *argv[])
 }
 
 static void
+set_packet_in_format(struct vconn *vconn,
+                     enum nx_packet_in_format packet_in_format)
+{
+    struct ofpbuf *spif = ofputil_make_set_packet_in_format(packet_in_format);
+    transact_noreply(vconn, spif);
+    VLOG_DBG("%s: using user-specified packet in format %s",
+             vconn_get_name(vconn),
+             ofputil_packet_in_format_to_string(packet_in_format));
+}
+
+static void
 monitor_vconn(struct vconn *vconn)
 {
     struct unixctl_server *server;
     bool exiting = false;
     int error, fd;
 
+    if (preferred_packet_in_format >= 0) {
+        set_packet_in_format(vconn, preferred_packet_in_format);
+    }
+
     /* Daemonization will close stderr but we really want to keep it, so make a
      * copy. */
     fd = dup(STDERR_FILENO);
-- 
1.7.7.1




More information about the dev mailing list