Please review this version.

Ethan

On Thu, Dec 29, 2011 at 16:05, Ethan Jackson <et...@nicira.com> wrote:
> 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 <et...@nicira.com>
> ---
>  include/openflow/nicira-ext.h |   46 +++++++++++++-
>  lib/learning-switch.c         |    2 +
>  lib/nx-match.h                |    2 +-
>  lib/ofp-print.c               |   34 ++++++++++
>  lib/ofp-util.c                |  143 
> ++++++++++++++++++++++++++++++++++++++---
>  lib/ofp-util.h                |   16 ++++-
>  ofproto/connmgr.c             |   25 +++++++-
>  ofproto/connmgr.h             |    3 +
>  ofproto/ofproto-dpif.c        |   43 ++++++++++---
>  ofproto/ofproto.c             |   27 ++++++++
>  ofproto/pktbuf.h              |    2 +-
>  tests/ofproto-dpif.at         |   72 ++++++++++----------
>  utilities/ovs-ofctl.8.in      |   20 ++++++
>  utilities/ovs-ofctl.c         |   30 +++++++++
>  14 files changed, 405 insertions(+), 60 deletions(-)
>
> diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
> index 1dcd32b..f511c6c 100644
> --- a/include/openflow/nicira-ext.h
> +++ b/include/openflow/nicira-ext.h
> @@ -162,7 +162,12 @@ 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,
> +
> +
> +    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 +251,45 @@ 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). */
> +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/nx-match.h b/lib/nx-match.h
> index c7ee0f8..fa4febb 100644
> --- a/lib/nx-match.h
> +++ b/lib/nx-match.h
> @@ -21,10 +21,10 @@
>  #include <sys/types.h>
>  #include <netinet/in.h>
>  #include "openvswitch/types.h"
> +#include "flow.h"
>
>  struct cls_rule;
>  struct ds;
> -struct flow;
>  struct ofpbuf;
>  struct nx_action_reg_load;
>  struct nx_action_reg_move;
> diff --git a/lib/ofp-print.c b/lib/ofp-print.c
> index 4c7321f..d88d9ef 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -84,6 +84,7 @@ ofp_print_packet_in(struct ds *string, const struct 
> ofp_header *oh,
>  {
>     struct ofputil_packet_in pin;
>     int error;
> +    int i;
>
>     error = ofputil_decode_packet_in(&pin, oh);
>     if (error) {
> @@ -91,9 +92,23 @@ 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.in_port, string);
>
> +    for (i = 0; i < FLOW_N_REGS; i++) {
> +        if (pin.regs[i]) {
> +            ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.regs[i]);
> +        }
> +    }
> +
>     if (pin.reason == OFPR_ACTION) {
>         ds_put_cstr(string, " (via action)");
>     } else if (pin.reason != OFPR_NO_MATCH) {
> @@ -1248,6 +1263,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)
> @@ -1294,6 +1323,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;
>
> @@ -1397,6 +1427,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 5a7b2a5..6d73755 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 *
> @@ -1563,6 +1616,38 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
>         pin->buffer_id = ntohl(opi->buffer_id);
>         pin->total_len = ntohs(opi->total_len);
>         pin->send_len = 0;
> +
> +        pin->table_id = 0;
> +        pin->cookie = 0;
> +        memset(pin->regs, 0, sizeof pin->regs);
> +    } else if (code == OFPUTIL_NXT_PACKET_IN) {
> +        const struct nxt_packet_in *npi = (const struct nxt_packet_in *) oh;
> +        uint16_t total_len = ntohs(npi->total_len);
> +        size_t match_len = ntohs(npi->match_len);
> +        struct ofpbuf nx_match;
> +        struct cls_rule rule;
> +        int error;
> +
> +        ofpbuf_use_const(&nx_match, (uint8_t *) npi + sizeof *npi,
> +                         ROUND_UP(match_len, 8));
> +        error = nx_pull_match(&nx_match, match_len, 0, &rule, NULL, NULL);
> +        if (error) {
> +            return error;
> +        }
> +
> +        ofpbuf_use_const(&pin->packet, ((uint8_t *) npi
> +                                        + ntohs(npi->nxh.header.length)
> +                                        - ntohs(npi->total_len)), total_len);
> +
> +        pin->in_port = rule.flow.in_port;
> +        pin->reason = npi->reason;
> +        pin->table_id = npi->table_id;
> +        pin->cookie = npi->cookie;
> +        memcpy(pin->regs, rule.flow.regs, sizeof pin->regs);
> +
> +        pin->buffer_id = ntohl(npi->buffer_id);
> +        pin->send_len = 0;
> +        pin->total_len = total_len;
>     } else {
>         NOT_REACHED();
>     }
> @@ -1585,10 +1670,10 @@ ofputil_decode_packet_in(struct ofputil_packet_in 
> *pin,
>  * payload. */
>  struct ofpbuf *
>  ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
> -                        struct ofpbuf *rw_packet)
> +                         struct ofpbuf *rw_packet,
> +                         enum nx_packet_in_format packet_in_format)
>  {
>     int total_len = pin->packet.size;
> -    struct ofp_packet_in opi;
>
>     if (rw_packet) {
>         if (pin->send_len < rw_packet->size) {
> @@ -1601,14 +1686,52 @@ ofputil_encode_packet_in(const struct 
> ofputil_packet_in *pin,
>     }
>
>     /* Add OFPT_PACKET_IN. */
> -    memset(&opi, 0, sizeof opi);
> -    opi.header.version = OFP_VERSION;
> -    opi.header.type = OFPT_PACKET_IN;
> -    opi.total_len = htons(total_len);
> -    opi.in_port = htons(pin->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) {
> +        struct ofp_packet_in opi;
> +
> +        memset(&opi, 0, sizeof opi);
> +        opi.header.version = OFP_VERSION;
> +        opi.header.type = OFPT_PACKET_IN;
> +        opi.total_len = htons(total_len);
> +        opi.in_port = htons(pin->in_port);
> +        opi.reason = pin->reason;
> +        opi.buffer_id = htonl(pin->buffer_id);
> +        ofpbuf_push(rw_packet, &opi, offsetof(struct ofp_packet_in, data));
> +    } else if (packet_in_format == NXPIF_NXM) {
> +        struct nxt_packet_in *npi;
> +        struct ofpbuf nx_match;
> +        struct cls_rule rule;
> +        size_t match_len;
> +        size_t i;
> +
> +        ofpbuf_init(&nx_match, 0);
> +        cls_rule_init_catchall(&rule, 0);
> +        cls_rule_set_in_port(&rule, pin->in_port);
> +        for (i = 0; i < FLOW_N_REGS; i++) {
> +            cls_rule_set_reg(&rule, i, pin->regs[i]);
> +        }
> +        match_len = nx_put_match(&nx_match, &rule, 0, 0);
> +
> +        ofpbuf_prealloc_headroom(rw_packet, sizeof *npi + nx_match.size + 2);
> +        ofpbuf_push_zeros(rw_packet, 2);
> +        ofpbuf_push(rw_packet, nx_match.data, nx_match.size);
> +        npi = ofpbuf_push_zeros(rw_packet, sizeof *npi);
> +        ofpbuf_uninit(&nx_match);
> +
> +        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(total_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 22dc325..f1e2c9d 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);
>
> @@ -217,6 +225,9 @@ struct ofputil_packet_in {
>     struct ofpbuf packet;       /* Const ofpbuf. */
>     uint16_t in_port;
>     uint8_t reason;             /* One of OFPR_*. */
> +    uint8_t table_id;
> +    ovs_be64 cookie;
> +    uint32_t regs[FLOW_N_REGS];
>
>     uint32_t buffer_id;
>     int send_len;
> @@ -226,7 +237,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 *rw_packet);
> +                                        struct ofpbuf *rw_packet,
> +                                        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 d32f5fd..e9f842d 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;
> @@ -1229,7 +1250,9 @@ 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, rw_packet),
> +                  flow->in_port,
> +                  ofputil_encode_packet_in(&pin, rw_packet,
> +                                           ofconn->packet_in_format),
>                   do_send_packet_in, ofconn);
>  }
>
> diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
> index 0224352..575c4df 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 9f8c88c..504e2dd 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -204,6 +204,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
> @@ -237,7 +240,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);
>
> @@ -2402,10 +2406,14 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, 
> struct ofpbuf *packet,
>
>     pin.in_port = flow->in_port;
>     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 */
>     pin.total_len = packet->size;
>     ofpbuf_use_const(&pin.packet, packet->data, packet->size);
> +    memset(pin.regs, 0, sizeof pin.regs);
>     connmgr_send_packet_in(ofproto->up.connmgr, &pin, flow,
>                            clone ? NULL : packet);
>  }
> @@ -3170,7 +3178,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));
> @@ -3359,7 +3368,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
> @@ -3509,7 +3519,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));
> @@ -3649,7 +3660,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;
> @@ -3927,7 +3938,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,
> @@ -4197,8 +4209,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--;
>         }
>
> @@ -4289,11 +4305,17 @@ execute_controller_action(struct action_xlate_ctx 
> *ctx, int len)
>     }
>
>     ofpbuf_use_const(&pin.packet, packet->data, packet->size);
> +
>     pin.in_port = ctx->flow.in_port;
>     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;
> +    memcpy(pin.regs, ctx->flow.regs, sizeof pin.regs);
> +
>     connmgr_send_packet_in(ctx->ofproto->up.connmgr, &pin, &ctx->flow, 
> packet);
>  }
>
> @@ -4693,13 +4715,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;
> @@ -5481,7 +5505,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);
> @@ -5771,7 +5795,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 b6f9207..98080a3 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 surpring 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/ofproto/pktbuf.h b/ofproto/pktbuf.h
> index 67f4973..5dc93eb 100644
> --- a/ofproto/pktbuf.h
> +++ b/ofproto/pktbuf.h
> @@ -26,7 +26,7 @@ int pktbuf_capacity(void);
>
>  struct pktbuf *pktbuf_create(void);
>  void pktbuf_destroy(struct pktbuf *);
> -uint32_t pktbuf_save(struct pktbuf *, struct ofpbuf *buffer, uint16_t 
> in_port);
> +uint32_t pktbuf_save(struct pktbuf *, struct ofpbuf *, uint16_t in_port);
>  uint32_t pktbuf_get_null(void);
>  int pktbuf_retrieve(struct pktbuf *, uint32_t id, struct ofpbuf **bufferp,
>                     uint16_t *in_port);
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index f17c882..0449009 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -172,16 +172,16 @@ OVS_VSWITCHD_START([dnl
>
>  AT_DATA([flows.txt], [dnl
>  cookie=0x0 dl_src=11:11:11:11:11:11 actions=controller
> -cookie=0x1 dl_src=22:22:22:22:22:22 actions=controller,resubmit:80
> +cookie=0x1 dl_src=22:22:22:22:22:22 actions=controller,resubmit(80,1)
>  cookie=0x2 dl_src=33: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:81: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:81: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[[]],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])
>
> @@ -243,7 +243,7 @@ priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) 
> mac(33:33:33:33:33:33->50:54
>  ])
>
>  dnl Checksum TCP.
> -AT_CHECK([ovs-ofctl monitor br0 65534 --detach --pidfile 2> 
> ofctl_monitor.log])AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> 
> ofctl_monitor.log])AT_CAPTURE_FILE([ofctl_monitor.log])
>
>  for i in 1 ; do
>     ovs-appctl netdev-dummy/receive p1 
> 'in_port(1),eth(src=22: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)'
> @@ -251,36 +251,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 (via action) 
> data_len=60 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(0) 
> mac(22: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 
> reg0=0x1 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(22: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 
> reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> 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(81: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 
> 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(81: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 
> 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(81: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 
> 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(81: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_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> 
> ofctl_monitor.log])AT_CAPTURE_FILE([ofctl_monitor.log])
>
>  for i in 1 ; do
>     ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 22 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'
> @@ -288,45 +288,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 (via action) 
> data_len=60 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(0) 
> mac(22: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 
> reg0=0x1 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(22: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 
> reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
>  priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
> mac(81: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 
> 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(81: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 
> 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(81: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 
> 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(81: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 
> 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(81: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 | sed 
> 's/duration=[[0-9]]*\.[[0-9]]*s,/duration=\<omitted\>,/' | sort], [0], [dnl
>  cookie=0x0, duration=<omitted>, table=0, n_packets=3, n_bytes=180, 
> dl_src=11:11:11:11:11:11 actions=CONTROLLER:65535
> - cookie=0x1, duration=<omitted>, table=0, n_packets=2, n_bytes=120, 
> dl_src=22:22:22:22:22:22 actions=CONTROLLER:65535,resubmit:80
> + cookie=0x1, duration=<omitted>, table=0, n_packets=2, n_bytes=120, 
> dl_src=22:22:22:22:22:22 actions=CONTROLLER:65535,resubmit(80,1)
>  cookie=0x2, duration=<omitted>, table=0, n_packets=3, n_bytes=180, 
> dl_src=33:33:33:33:33:33 actions=mod_vlan_vid:15,CONTROLLER:65535
> - cookie=0x3, duration=<omitted>, table=0, n_packets=2, n_bytes=120, 
> in_port=80 actions=mod_vlan_vid:80,CONTROLLER:65535,resubmit:81
> - cookie=0x4, duration=<omitted>, table=0, n_packets=2, n_bytes=120, 
> in_port=81 actions=mod_dl_src:81:81:81:81:81:81,CONTROLLER:65535,resubmit:82
> - cookie=0x5, duration=<omitted>, 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=<omitted>, 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=<omitted>, 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=<omitted>, table=0, n_packets=2, n_bytes=120, 
> in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit:86
> - cookie=0x9, duration=<omitted>, table=0, n_packets=2, n_bytes=120, 
> in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
> + cookie=0x3, duration=<omitted>, 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=<omitted>, table=2, n_packets=2, n_bytes=120, 
> in_port=81 
> actions=load:0x2->NXM_NX_REG1[[]],mod_dl_src:81:81:81:81:81:81,CONTROLLER:65535,resubmit(82,3)
> + cookie=0x5, duration=<omitted>, 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=<omitted>, 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=<omitted>, table=5, n_packets=2, n_bytes=120, 
> in_port=84 
> actions=load:0x5->NXM_NX_REG4[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6)
> + cookie=0x8, duration=<omitted>, table=6, n_packets=2, n_bytes=120, 
> in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7)
> + cookie=0x9, duration=<omitted>, 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 15bdbee..1b5c979 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
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to