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

Ethan Jackson ethan at nicira.com
Thu Dec 29 21:06:05 UTC 2011


Please review this version.

Ethan

On Thu, Dec 29, 2011 at 16:05, Ethan Jackson <ethan at 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 <ethan at 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
>



More information about the dev mailing list