[ovs-dev] [of1.1 v3 04/13] Introduce ofpacts, an abstraction of OpenFlow actions.
Pravin Shelar
pshelar at nicira.com
Tue Jul 3 23:14:27 UTC 2012
Patch looks pretty good, here are few comments:-
Why have you added explicit OFPACT_END action, why not use action_len
to find END?
------
autopath_to_openflow()
learn_to_openflow()
multipath_to_openflow()
I am not sure these function are not nameed line *_to_nsast().
------
why not store action arg, like vlan id, tunnel id, in network byte
order, so that we do not need to convert it back to network order
while executing actions?
------
nxm_decode(), nxm_decode_discrete() can be removed.
------
can we avoid xmemdup() in ofproto_add_flow()?
------
in handle_flow_stats_request() we need to set ofpacts_len.
------
why is ofpact_fin_timeout added in learn_execute and not in
learn_from_openflow()?
in general do you think it is worth moving more and more stuff from
ofpact_check to ofproto decode step?
------
Thanks,
Pravin.
On Tue, Jun 26, 2012 at 11:53 PM, Ben Pfaff <blp at nicira.com> wrote:
> OpenFlow actions have always been somewhat awkward to handle.
> Moreover, over time we've started creating actions that require more
> complicated parsing. When we maintain those actions internally in
> their wire format, we end up parsing them multiple times, whenever
> we have to look at the set of actions.
>
> When we add support for OpenFlow 1.1 or later protocols, the situation
> will get worse, because these newer protocols support many of the same
> actions but with different representations. It becomes unrealistic to
> handle each protocol in its wire format.
>
> This commit adopts a new strategy, by converting OpenFlow actions into
> an internal form from the wire format when they are read, and converting
> them back to the wire format when flows are dumped. I believe that this
> will be more maintainable over time.
>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
>
> ---
>
> v2:
>
> - Fix confusion between NXAST_RESUBMIT and NXAST_RESUBMIT_TABLE.
>
> - Rename functions for NXAST_ actions to mention nxast in their
> names instead of openflow10, since they are not OpenFlow 1.0
> specific.
>
> - Move the code for NXAST_ encoding into a separate function so
> that later on it can be reused for encoding these actions into
> OpenFlow 1.1 also.
> ---
> DESIGN | 20 +
> lib/automake.mk | 2 +
> lib/autopath.c | 70 ++--
> lib/autopath.h | 15 +-
> lib/bundle.c | 277 ++++++-----
> lib/bundle.h | 26 +-
> lib/compiler.h | 20 +-
> lib/learn.c | 672 ++++++++++++-------------
> lib/learn.h | 17 +-
> lib/learning-switch.c | 99 ++--
> lib/multipath.c | 160 ++++---
> lib/multipath.h | 18 +-
> lib/nx-match.c | 200 ++++----
> lib/nx-match.h | 31 +-
> lib/ofp-actions.c | 1213 ++++++++++++++++++++++++++++++++++++++++++++
> lib/ofp-actions.h | 479 +++++++++++++++++
> lib/ofp-parse.c | 252 +++++-----
> lib/ofp-parse.h | 2 +-
> lib/ofp-print.c | 291 +----------
> lib/ofp-print.h | 2 -
> lib/ofp-util.c | 474 ++++--------------
> lib/ofp-util.h | 61 +--
> ofproto/connmgr.c | 15 +-
> ofproto/fail-open.c | 14 +-
> ofproto/ofproto-dpif.c | 398 +++++++--------
> ofproto/ofproto-provider.h | 33 +-
> ofproto/ofproto.c | 121 +++---
> tests/learn.at | 4 +-
> tests/test-bundle.c | 55 +--
> tests/test-multipath.c | 11 +-
> utilities/ovs-ofctl.c | 54 +-
> 31 files changed, 3119 insertions(+), 1987 deletions(-)
> create mode 100644 lib/ofp-actions.c
> create mode 100644 lib/ofp-actions.h
>
> diff --git a/DESIGN b/DESIGN
> index a3a62b2..8dfc1ff 100644
> --- a/DESIGN
> +++ b/DESIGN
> @@ -612,6 +612,26 @@ The following are explicitly *not* supported by in-band control:
> gateway.
>
>
> +Action Reproduction
> +===================
> +
> +It seems likely that many controllers, at least at startup, use the
> +OpenFlow "flow statistics" request to obtain existing flows, then
> +compare the flows' actions against the actions that they expect to
> +find. Before version 1.8.0, Open vSwitch always returned exact,
> +byte-for-byte copies of the actions that had been added to the flow
> +table. The current version of Open vSwitch does not always do this in
> +some exceptional cases. This section lists the exceptions that
> +controller authors must keep in mind if they compare actual actions
> +against desired actions in a bytewise fashion:
> +
> + - Open vSwitch zeros padding bytes in action structures,
> + regardless of their values when the flows were added.
> +
> +Please report other discrepancies, if you notice any, so that we can
> +fix or document them.
> +
> +
> Suggestions
> ===========
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 9d8b426..641a2f7 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -96,6 +96,8 @@ lib_libopenvswitch_a_SOURCES = \
> lib/nx-match.h \
> lib/odp-util.c \
> lib/odp-util.h \
> + lib/ofp-actions.c \
> + lib/ofp-actions.h \
> lib/ofp-errors.c \
> lib/ofp-errors.h \
> lib/ofp-parse.c \
> diff --git a/lib/autopath.c b/lib/autopath.c
> index 9511a6d..3d9b350 100644
> --- a/lib/autopath.c
> +++ b/lib/autopath.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2011 Nicira, Inc.
> + * Copyright (c) 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -24,6 +24,7 @@
> #include "flow.h"
> #include "meta-flow.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "openflow/nicira-ext.h"
> @@ -31,32 +32,21 @@
>
> VLOG_DEFINE_THIS_MODULE(autopath);
>
> -/* Loads 'ofp_port' into the appropriate register in accordance with the
> - * autopath action. */
> void
> -autopath_execute(const struct nx_action_autopath *ap, struct flow *flow,
> - uint16_t ofp_port)
> -{
> - struct mf_subfield dst;
> -
> - nxm_decode(&dst, ap->dst, ap->ofs_nbits);
> - mf_set_subfield_value(&dst, ofp_port, flow);
> -}
> -
> -void
> -autopath_parse(struct nx_action_autopath *ap, const char *s_)
> +autopath_parse(struct ofpact_autopath *ap, const char *s_)
> {
> char *s;
> - char *id_str, *dst_s, *save_ptr;
> - struct mf_subfield dst;
> int id_int;
> + char *id_str, *dst, *save_ptr;
> +
> + ofpact_init_AUTOPATH(ap);
>
> s = xstrdup(s_);
> save_ptr = NULL;
> id_str = strtok_r(s, ", ", &save_ptr);
> - dst_s = strtok_r(NULL, ", ", &save_ptr);
> + dst = strtok_r(NULL, ", ", &save_ptr);
>
> - if (!dst_s) {
> + if (!dst) {
> ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
> }
>
> @@ -65,33 +55,51 @@ autopath_parse(struct nx_action_autopath *ap, const char *s_)
> ovs_fatal(0, "%s: autopath id %d is not in valid range "
> "1 to %"PRIu32, s_, id_int, UINT32_MAX);
> }
> + ap->port = id_int;
>
> - mf_parse_subfield(&dst, dst_s);
> - if (dst.n_bits < 16) {
> + mf_parse_subfield(&ap->dst, dst);
> + if (ap->dst.n_bits < 16) {
> ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
> "less than required 65536",
> - s_, dst.n_bits, 1u << dst.n_bits);
> + s_, ap->dst.n_bits, 1u << ap->dst.n_bits);
> }
>
> - ofputil_init_NXAST_AUTOPATH(ap);
> - ap->id = htonl(id_int);
> - ap->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
> - ap->dst = htonl(dst.field->nxm_header);
> -
> free(s);
> }
>
> enum ofperr
> -autopath_check(const struct nx_action_autopath *ap, const struct flow *flow)
> +autopath_from_openflow(const struct nx_action_autopath *nap,
> + struct ofpact_autopath *autopath)
> {
> - struct mf_subfield dst;
> + ofpact_init_AUTOPATH(autopath);
> + autopath->dst.field = mf_from_nxm_header(ntohl(nap->dst));
> + autopath->dst.ofs = nxm_decode_ofs(nap->ofs_nbits);
> + autopath->dst.n_bits = nxm_decode_n_bits(nap->ofs_nbits);
> + autopath->port = ntohl(nap->id);
>
> - nxm_decode(&dst, ap->dst, ap->ofs_nbits);
> - if (dst.n_bits < 16) {
> + if (autopath->dst.n_bits < 16) {
> VLOG_WARN("at least 16 bit destination is required for autopath "
> "action.");
> return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - return mf_check_dst(&dst, flow);
> + return autopath_check(autopath, NULL);
> +}
> +
> +enum ofperr
> +autopath_check(const struct ofpact_autopath *autopath, const struct flow *flow)
> +{
> + return mf_check_dst(&autopath->dst, flow);
> +}
> +
> +void
> +autopath_to_openflow(const struct ofpact_autopath *autopath,
> + struct ofpbuf *openflow)
> +{
> + struct nx_action_autopath *ap = ofputil_put_NXAST_AUTOPATH(openflow);
> +
> + ap->ofs_nbits = nxm_encode_ofs_nbits(autopath->dst.ofs,
> + autopath->dst.n_bits);
> + ap->dst = htonl(autopath->dst.field->nxm_header);
> + ap->id = htonl(autopath->port);
> }
> diff --git a/lib/autopath.h b/lib/autopath.h
> index 480d40a..b23c13f 100644
> --- a/lib/autopath.h
> +++ b/lib/autopath.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2011 Nicira, Inc.
> + * Copyright (c) 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -22,15 +22,20 @@
>
> struct flow;
> struct nx_action_autopath;
> +struct ofpact_autopath;
> +struct ofpbuf;
>
> /* NXAST_AUTOPATH helper functions.
> *
> * See include/openflow/nicira-ext.h for NXAST_AUTOPATH specification. */
>
> -void autopath_execute(const struct nx_action_autopath *, struct flow *,
> - uint16_t ofp_port);
> -void autopath_parse(struct nx_action_autopath *, const char *);
> -enum ofperr autopath_check(const struct nx_action_autopath *,
> +void autopath_parse(struct ofpact_autopath *, const char *);
> +
> +enum ofperr autopath_from_openflow(const struct nx_action_autopath *,
> + struct ofpact_autopath *);
> +enum ofperr autopath_check(const struct ofpact_autopath *,
> const struct flow *);
> +void autopath_to_openflow(const struct ofpact_autopath *,
> + struct ofpbuf *openflow);
>
> #endif /* autopath.h */
> diff --git a/lib/bundle.c b/lib/bundle.c
> index a205974..830c002 100644
> --- a/lib/bundle.c
> +++ b/lib/bundle.c
> @@ -25,6 +25,7 @@
> #include "meta-flow.h"
> #include "nx-match.h"
> #include "ofpbuf.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "openflow/nicira-ext.h"
> @@ -35,14 +36,13 @@
> VLOG_DEFINE_THIS_MODULE(bundle);
>
> static uint16_t
> -execute_ab(const struct nx_action_bundle *nab,
> +execute_ab(const struct ofpact_bundle *bundle,
> bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux)
> {
> size_t i;
>
> - for (i = 0; i < ntohs(nab->n_slaves); i++) {
> - uint16_t slave = bundle_get_slave(nab, i);
> -
> + for (i = 0; i < bundle->n_slaves; i++) {
> + uint16_t slave = bundle->slaves[i];
> if (slave_enabled(slave, aux)) {
> return slave;
> }
> @@ -52,18 +52,18 @@ execute_ab(const struct nx_action_bundle *nab,
> }
>
> static uint16_t
> -execute_hrw(const struct nx_action_bundle *nab, const struct flow *flow,
> +execute_hrw(const struct ofpact_bundle *bundle, const struct flow *flow,
> bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux)
> {
> uint32_t flow_hash, best_hash;
> int best, i;
>
> - flow_hash = flow_hash_fields(flow, ntohs(nab->fields), ntohs(nab->basis));
> + flow_hash = flow_hash_fields(flow, bundle->fields, bundle->basis);
> best = -1;
> best_hash = 0;
>
> - for (i = 0; i < ntohs(nab->n_slaves); i++) {
> - if (slave_enabled(bundle_get_slave(nab, i), aux)) {
> + for (i = 0; i < bundle->n_slaves; i++) {
> + if (slave_enabled(bundle->slaves[i], aux)) {
> uint32_t hash = hash_2words(i, flow_hash);
>
> if (best < 0 || hash > best_hash) {
> @@ -73,33 +73,26 @@ execute_hrw(const struct nx_action_bundle *nab, const struct flow *flow,
> }
> }
>
> - return best >= 0 ? bundle_get_slave(nab, best) : OFPP_NONE;
> + return best >= 0 ? bundle->slaves[best] : OFPP_NONE;
> }
>
> -/* Executes 'nab' on 'flow'. Uses 'slave_enabled' to determine if the slave
> +/* Executes 'bundle' on 'flow'. Uses 'slave_enabled' to determine if the slave
> * designated by 'ofp_port' is up. Returns the chosen slave, or OFPP_NONE if
> * none of the slaves are acceptable. */
> uint16_t
> -bundle_execute(const struct nx_action_bundle *nab, const struct flow *flow,
> +bundle_execute(const struct ofpact_bundle *bundle, const struct flow *flow,
> bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux)
> {
> - switch (ntohs(nab->algorithm)) {
> - case NX_BD_ALG_HRW: return execute_hrw(nab, flow, slave_enabled, aux);
> - case NX_BD_ALG_ACTIVE_BACKUP: return execute_ab(nab, slave_enabled, aux);
> - default: NOT_REACHED();
> - }
> -}
> + switch (bundle->algorithm) {
> + case NX_BD_ALG_HRW:
> + return execute_hrw(bundle, flow, slave_enabled, aux);
>
> -void
> -bundle_execute_load(const struct nx_action_bundle *nab, struct flow *flow,
> - bool (*slave_enabled)(uint16_t ofp_port, void *aux),
> - void *aux)
> -{
> - struct mf_subfield dst;
> + case NX_BD_ALG_ACTIVE_BACKUP:
> + return execute_ab(bundle, slave_enabled, aux);
>
> - nxm_decode(&dst, nab->dst, nab->ofs_nbits);
> - mf_set_subfield_value(&dst, bundle_execute(nab, flow, slave_enabled, aux),
> - flow);
> + default:
> + NOT_REACHED();
> + }
> }
>
> /* Checks that 'nab' specifies a bundle action which is supported by this
> @@ -107,41 +100,43 @@ bundle_execute_load(const struct nx_action_bundle *nab, struct flow *flow,
> * ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an
> * OFPERR_* error code. */
> enum ofperr
> -bundle_check(const struct nx_action_bundle *nab, int max_ports,
> - const struct flow *flow)
> +bundle_from_openflow(const struct nx_action_bundle *nab,
> + struct ofpbuf *ofpacts)
> {
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> - uint16_t n_slaves, fields, algorithm, subtype;
> + struct ofpact_bundle *bundle;
> + uint16_t subtype;
> uint32_t slave_type;
> size_t slaves_size, i;
> enum ofperr error;
>
> + bundle = ofpact_put_BUNDLE(ofpacts);
> +
> subtype = ntohs(nab->subtype);
> - n_slaves = ntohs(nab->n_slaves);
> - fields = ntohs(nab->fields);
> - algorithm = ntohs(nab->algorithm);
> + bundle->n_slaves = ntohs(nab->n_slaves);
> + bundle->basis = ntohs(nab->basis);
> + bundle->fields = ntohs(nab->fields);
> + bundle->algorithm = ntohs(nab->algorithm);
> slave_type = ntohl(nab->slave_type);
> slaves_size = ntohs(nab->len) - sizeof *nab;
>
> error = OFPERR_OFPBAC_BAD_ARGUMENT;
> - if (!flow_hash_fields_valid(fields)) {
> - VLOG_WARN_RL(&rl, "unsupported fields %"PRIu16, fields);
> - } else if (n_slaves > BUNDLE_MAX_SLAVES) {
> + if (!flow_hash_fields_valid(bundle->fields)) {
> + VLOG_WARN_RL(&rl, "unsupported fields %d", (int) bundle->fields);
> + } else if (bundle->n_slaves > BUNDLE_MAX_SLAVES) {
> VLOG_WARN_RL(&rl, "too may slaves");
> - } else if (algorithm != NX_BD_ALG_HRW
> - && algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
> - VLOG_WARN_RL(&rl, "unsupported algorithm %"PRIu16, algorithm);
> + } else if (bundle->algorithm != NX_BD_ALG_HRW
> + && bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
> + VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) bundle->algorithm);
> } else if (slave_type != NXM_OF_IN_PORT) {
> VLOG_WARN_RL(&rl, "unsupported slave type %"PRIu16, slave_type);
> } else {
> error = 0;
> }
>
> - for (i = 0; i < sizeof(nab->zero); i++) {
> - if (nab->zero[i]) {
> - VLOG_WARN_RL(&rl, "reserved field is nonzero");
> - error = OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> + if (!is_all_zeros(nab->zero, sizeof nab->zero)) {
> + VLOG_WARN_RL(&rl, "reserved field is nonzero");
> + error = OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> if (subtype == NXAST_BUNDLE && (nab->ofs_nbits || nab->dst)) {
> @@ -150,34 +145,61 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
> }
>
> if (subtype == NXAST_BUNDLE_LOAD) {
> - struct mf_subfield dst;
> + bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst));
> + bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits);
> + bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits);
>
> - nxm_decode(&dst, nab->dst, nab->ofs_nbits);
> - if (dst.n_bits < 16) {
> + if (bundle->dst.n_bits < 16) {
> VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit "
> "destination.");
> error = OFPERR_OFPBAC_BAD_ARGUMENT;
> - } else if (!error) {
> - error = mf_check_dst(&dst, flow);
> }
> }
>
> - if (slaves_size < n_slaves * sizeof(ovs_be16)) {
> + if (slaves_size < bundle->n_slaves * sizeof(ovs_be16)) {
> VLOG_WARN_RL(&rl, "Nicira action %"PRIu16" only has %zu bytes "
> "allocated for slaves. %zu bytes are required for "
> "%"PRIu16" slaves.", subtype, slaves_size,
> - n_slaves * sizeof(ovs_be16), n_slaves);
> + bundle->n_slaves * sizeof(ovs_be16), bundle->n_slaves);
> error = OFPERR_OFPBAC_BAD_LEN;
> }
>
> - for (i = 0; i < n_slaves; i++) {
> - uint16_t ofp_port = bundle_get_slave(nab, i);
> - enum ofperr ofputil_error;
> + for (i = 0; i < bundle->n_slaves; i++) {
> + uint16_t ofp_port = ntohs(((ovs_be16 *)(nab + 1))[i]);
> + ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port);
> + }
> +
> + bundle = ofpacts->l2;
> + ofpact_update_len(ofpacts, &bundle->ofpact);
> +
> + if (!error) {
> + error = bundle_check(bundle, OFPP_MAX, NULL);
> + }
> + return error;
> +}
> +
> +enum ofperr
> +bundle_check(const struct ofpact_bundle *bundle, int max_ports,
> + const struct flow *flow)
> +{
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> + size_t i;
> +
> + if (bundle->dst.field) {
> + enum ofperr error = mf_check_dst(&bundle->dst, flow);
> + if (error) {
> + return error;
> + }
> + }
> +
> + for (i = 0; i < bundle->n_slaves; i++) {
> + uint16_t ofp_port = bundle->slaves[i];
> + enum ofperr error;
>
> - ofputil_error = ofputil_check_output_port(ofp_port, max_ports);
> - if (ofputil_error) {
> + error = ofputil_check_output_port(ofp_port, max_ports);
> + if (error) {
> VLOG_WARN_RL(&rl, "invalid slave %"PRIu16, ofp_port);
> - error = ofputil_error;
> + return error;
> }
>
> /* Controller slaves are unsupported due to the lack of a max_len
> @@ -185,23 +207,50 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
> * seem to be a real-world use-case for supporting it. */
> if (ofp_port == OFPP_CONTROLLER) {
> VLOG_WARN_RL(&rl, "unsupported controller slave");
> - error = OFPERR_OFPBAC_BAD_OUT_PORT;
> + return OFPERR_OFPBAC_BAD_OUT_PORT;
> }
> }
>
> - return error;
> + return 0;
> +}
> +
> +void
> +bundle_to_openflow(const struct ofpact_bundle *bundle, struct ofpbuf *openflow)
> +{
> + int slaves_len = ROUND_UP(bundle->n_slaves, OFP_ACTION_ALIGN);
> + struct nx_action_bundle *nab;
> + ovs_be16 *slaves;
> + size_t i;
> +
> + nab = (bundle->dst.field
> + ? ofputil_put_NXAST_BUNDLE_LOAD(openflow)
> + : ofputil_put_NXAST_BUNDLE(openflow));
> + nab->len = htons(ntohs(nab->len) + slaves_len);
> + nab->algorithm = htons(bundle->algorithm);
> + nab->fields = htons(bundle->fields);
> + nab->basis = htons(bundle->basis);
> + nab->slave_type = htonl(NXM_OF_IN_PORT);
> + nab->n_slaves = htons(bundle->n_slaves);
> + if (bundle->dst.field) {
> + nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs,
> + bundle->dst.n_bits);
> + nab->dst = htonl(bundle->dst.field->nxm_header);
> + }
> +
> + slaves = ofpbuf_put_zeros(openflow, slaves_len);
> + for (i = 0; i < bundle->n_slaves; i++) {
> + slaves[i] = htons(bundle->slaves[i]);
> + }
> }
>
> /* Helper for bundle_parse and bundle_parse_load. */
> static void
> -bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr,
> +bundle_parse__(const char *s, char **save_ptr,
> const char *fields, const char *basis, const char *algorithm,
> - const char *slave_type, const char *dst_s,
> - const char *slave_delim)
> + const char *slave_type, const char *dst,
> + const char *slave_delim, struct ofpbuf *ofpacts)
> {
> - enum ofputil_action_code code;
> - struct nx_action_bundle *nab;
> - uint16_t n_slaves;
> + struct ofpact_bundle *bundle;
>
> if (!slave_delim) {
> ovs_fatal(0, "%s: not enough arguments to bundle action", s);
> @@ -212,72 +261,56 @@ bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr,
> s, slave_delim);
> }
>
> - code = dst_s ? OFPUTIL_NXAST_BUNDLE_LOAD : OFPUTIL_NXAST_BUNDLE;
> - b->l2 = ofputil_put_action(code, b);
> + bundle = ofpact_put_BUNDLE(ofpacts);
>
> - n_slaves = 0;
> for (;;) {
> - ovs_be16 slave_be;
> + uint16_t slave_port;
> char *slave;
>
> slave = strtok_r(NULL, ", [", save_ptr);
> - if (!slave || n_slaves >= BUNDLE_MAX_SLAVES) {
> + if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
> break;
> }
>
> - slave_be = htons(atoi(slave));
> - ofpbuf_put(b, &slave_be, sizeof slave_be);
> + slave_port = atoi(slave);
> + ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
>
> - n_slaves++;
> + bundle = ofpacts->l2;
> + bundle->n_slaves++;
> }
> + ofpact_update_len(ofpacts, &bundle->ofpact);
>
> - /* Slaves array must be multiple of 8 bytes long. */
> - if (b->size % 8) {
> - ofpbuf_put_zeros(b, 8 - (b->size % 8));
> - }
> -
> - nab = b->l2;
> - nab->len = htons(b->size - ((char *) b->l2 - (char *) b->data));
> - nab->n_slaves = htons(n_slaves);
> - nab->basis = htons(atoi(basis));
> + bundle->basis = atoi(basis);
>
> if (!strcasecmp(fields, "eth_src")) {
> - nab->fields = htons(NX_HASH_FIELDS_ETH_SRC);
> + bundle->fields = NX_HASH_FIELDS_ETH_SRC;
> } else if (!strcasecmp(fields, "symmetric_l4")) {
> - nab->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4);
> + bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
> } else {
> ovs_fatal(0, "%s: unknown fields `%s'", s, fields);
> }
>
> if (!strcasecmp(algorithm, "active_backup")) {
> - nab->algorithm = htons(NX_BD_ALG_ACTIVE_BACKUP);
> + bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP;
> } else if (!strcasecmp(algorithm, "hrw")) {
> - nab->algorithm = htons(NX_BD_ALG_HRW);
> + bundle->algorithm = NX_BD_ALG_HRW;
> } else {
> ovs_fatal(0, "%s: unknown algorithm `%s'", s, algorithm);
> }
>
> - if (!strcasecmp(slave_type, "ofport")) {
> - nab->slave_type = htonl(NXM_OF_IN_PORT);
> - } else {
> + if (strcasecmp(slave_type, "ofport")) {
> ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type);
> }
>
> - if (dst_s) {
> - struct mf_subfield dst;
> -
> - mf_parse_subfield(&dst, dst_s);
> - nab->dst = htonl(dst.field->nxm_header);
> - nab->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
> + if (dst) {
> + mf_parse_subfield(&bundle->dst, dst);
> }
> -
> - b->l2 = NULL;
> }
>
> /* Converts a bundle action string contained in 's' to an nx_action_bundle and
> * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
> void
> -bundle_parse(struct ofpbuf *b, const char *s)
> +bundle_parse(const char *s, struct ofpbuf *ofpacts)
> {
> char *fields, *basis, *algorithm, *slave_type, *slave_delim;
> char *tokstr, *save_ptr;
> @@ -290,15 +323,15 @@ bundle_parse(struct ofpbuf *b, const char *s)
> slave_type = strtok_r(NULL, ", ", &save_ptr);
> slave_delim = strtok_r(NULL, ": ", &save_ptr);
>
> - bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, NULL,
> - slave_delim);
> + bundle_parse__(s, &save_ptr, fields, basis, algorithm, slave_type, NULL,
> + slave_delim, ofpacts);
> free(tokstr);
> }
>
> /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
> * and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
> void
> -bundle_parse_load(struct ofpbuf *b, const char *s)
> +bundle_parse_load(const char *s, struct ofpbuf *ofpacts)
> {
> char *fields, *basis, *algorithm, *slave_type, *dst, *slave_delim;
> char *tokstr, *save_ptr;
> @@ -312,22 +345,22 @@ bundle_parse_load(struct ofpbuf *b, const char *s)
> dst = strtok_r(NULL, ", ", &save_ptr);
> slave_delim = strtok_r(NULL, ": ", &save_ptr);
>
> - bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, dst,
> - slave_delim);
> + bundle_parse__(s, &save_ptr, fields, basis, algorithm, slave_type, dst,
> + slave_delim, ofpacts);
>
> free(tokstr);
> }
>
> /* Appends a human-readable representation of 'nab' to 's'. */
> void
> -bundle_format(const struct nx_action_bundle *nab, struct ds *s)
> +bundle_format(const struct ofpact_bundle *bundle, struct ds *s)
> {
> - const char *action, *fields, *algorithm, *slave_type;
> + const char *action, *fields, *algorithm;
> size_t i;
>
> - fields = flow_hash_fields_to_str(ntohs(nab->fields));
> + fields = flow_hash_fields_to_str(bundle->fields);
>
> - switch (ntohs(nab->algorithm)) {
> + switch (bundle->algorithm) {
> case NX_BD_ALG_HRW:
> algorithm = "hrw";
> break;
> @@ -338,43 +371,23 @@ bundle_format(const struct nx_action_bundle *nab, struct ds *s)
> algorithm = "<unknown>";
> }
>
> - switch (ntohl(nab->slave_type)) {
> - case NXM_OF_IN_PORT:
> - slave_type = "ofport";
> - break;
> - default:
> - slave_type = "<unknown>";
> - }
> -
> - switch (ntohs(nab->subtype)) {
> - case NXAST_BUNDLE:
> - action = "bundle";
> - break;
> - case NXAST_BUNDLE_LOAD:
> - action = "bundle_load";
> - break;
> - default:
> - NOT_REACHED();
> - }
> + action = bundle->dst.field ? "bundle_load" : "bundle";
>
> ds_put_format(s, "%s(%s,%"PRIu16",%s,%s,", action, fields,
> - ntohs(nab->basis), algorithm, slave_type);
> -
> - if (nab->subtype == htons(NXAST_BUNDLE_LOAD)) {
> - struct mf_subfield dst;
> + bundle->basis, algorithm, "ofport");
>
> - nxm_decode(&dst, nab->dst, nab->ofs_nbits);
> - mf_format_subfield(&dst, s);
> + if (bundle->dst.field) {
> + mf_format_subfield(&bundle->dst, s);
> ds_put_cstr(s, ",");
> }
>
> ds_put_cstr(s, "slaves:");
> - for (i = 0; i < ntohs(nab->n_slaves); i++) {
> + for (i = 0; i < bundle->n_slaves; i++) {
> if (i) {
> ds_put_cstr(s, ",");
> }
>
> - ds_put_format(s, "%"PRIu16, bundle_get_slave(nab, i));
> + ds_put_format(s, "%"PRIu16, bundle->slaves[i]);
> }
>
> ds_put_cstr(s, ")");
> diff --git a/lib/bundle.h b/lib/bundle.h
> index 4c0dff5..6d07b33 100644
> --- a/lib/bundle.h
> +++ b/lib/bundle.h
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2011 Nicira, Inc.
> +/* Copyright (c) 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -27,29 +27,23 @@
>
> struct ds;
> struct flow;
> +struct ofpact_bundle;
> struct ofpbuf;
>
> /* NXAST_BUNDLE helper functions.
> *
> * See include/openflow/nicira-ext.h for NXAST_BUNDLE specification. */
>
> -uint16_t bundle_execute(const struct nx_action_bundle *, const struct flow *,
> +uint16_t bundle_execute(const struct ofpact_bundle *, const struct flow *,
> bool (*slave_enabled)(uint16_t ofp_port, void *aux),
> void *aux);
> -void bundle_execute_load(const struct nx_action_bundle *, struct flow *,
> - bool (*slave_enabled)(uint16_t ofp_port, void *aux),
> - void *aux);
> -enum ofperr bundle_check(const struct nx_action_bundle *, int max_ports,
> +enum ofperr bundle_from_openflow(const struct nx_action_bundle *,
> + struct ofpbuf *ofpact);
> +enum ofperr bundle_check(const struct ofpact_bundle *, int max_ports,
> const struct flow *);
> -void bundle_parse(struct ofpbuf *, const char *);
> -void bundle_parse_load(struct ofpbuf *b, const char *);
> -void bundle_format(const struct nx_action_bundle *, struct ds *);
> -
> -/* Returns the 'i'th slave in 'nab'. */
> -static inline uint16_t
> -bundle_get_slave(const struct nx_action_bundle *nab, size_t i)
> -{
> - return ntohs(((ovs_be16 *)(nab + 1))[i]);
> -}
> +void bundle_to_openflow(const struct ofpact_bundle *, struct ofpbuf *of10);
> +void bundle_parse(const char *, struct ofpbuf *ofpacts);
> +void bundle_parse_load(const char *, struct ofpbuf *ofpacts);
> +void bundle_format(const struct ofpact_bundle *, struct ds *);
>
> #endif /* bundle.h */
> diff --git a/lib/compiler.h b/lib/compiler.h
> index 75e8610..27612a7 100644
> --- a/lib/compiler.h
> +++ b/lib/compiler.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -37,4 +37,22 @@
> #define SENTINEL(N)
> #endif
>
> +/* ISO C says that a C implementation may choose any integer type for an enum
> + * that is sufficient to hold all of its values. Common ABIs (such as the
> + * System V ABI used on i386 GNU/Linux) always use a full-sized "int", even
> + * when a smaller type would suffice.
> + *
> + * In GNU C, "enum __attribute__((packed)) name { ... }" defines 'name' as an
> + * enum compatible with a type that is no bigger than necessary. This is the
> + * intended use of OVS_PACKED_ENUM.
> + *
> + * OVS_PACKED_ENUM is intended for use only as a space optimization, since it
> + * only works with GCC. That means that it must not be used in wire protocols
> + * or otherwise exposed outside of a single process. */
> +#if __GNUC__ && !__CHECKER__
> +#define OVS_PACKED_ENUM __attribute__((__packed__))
> +#else
> +#define OVS_PACKED_ENUM
> +#endif
> +
> #endif /* compiler.h */
> diff --git a/lib/learn.c b/lib/learn.c
> index 5478b74..7dd02d0 100644
> --- a/lib/learn.c
> +++ b/lib/learn.c
> @@ -22,6 +22,7 @@
> #include "dynamic-string.h"
> #include "meta-flow.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> @@ -46,19 +47,6 @@ get_be32(const void **pp)
> return value;
> }
>
> -static uint64_t
> -get_bits(int n_bits, const void **p)
> -{
> - int n_segs = DIV_ROUND_UP(n_bits, 16);
> - uint64_t value;
> -
> - value = 0;
> - while (n_segs-- > 0) {
> - value = (value << 16) | ntohs(get_be16(p));
> - }
> - return value;
> -}
> -
> static void
> get_subfield(int n_bits, const void **p, struct mf_subfield *sf)
> {
> @@ -90,105 +78,85 @@ learn_min_len(uint16_t header)
> return min_len;
> }
>
> -static enum ofperr
> -learn_check_header(uint16_t header, size_t len)
> +/* Converts 'nal' into a "struct ofpact_learn" and appends that struct to
> + * 'ofpacts'. Returns 0 if successful, otherwise an OFPERR_*. */
> +enum ofperr
> +learn_from_openflow(const struct nx_action_learn *nal, struct ofpbuf *ofpacts)
> {
> - int src_type = header & NX_LEARN_SRC_MASK;
> - int dst_type = header & NX_LEARN_DST_MASK;
> + struct ofpact_learn *learn;
> + const void *p, *end;
>
> - /* Check for valid src and dst type combination. */
> - if (dst_type == NX_LEARN_DST_MATCH ||
> - dst_type == NX_LEARN_DST_LOAD ||
> - (dst_type == NX_LEARN_DST_OUTPUT &&
> - src_type == NX_LEARN_SRC_FIELD)) {
> - /* OK. */
> - } else {
> + if (nal->pad) {
> return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - /* Check that the arguments don't overrun the end of the action. */
> - if (len < learn_min_len(header)) {
> - return OFPERR_OFPBAC_BAD_LEN;
> - }
> + learn = ofpact_put_LEARN(ofpacts);
>
> - return 0;
> -}
> -
> -/* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
> - * valid action on 'flow'. */
> -enum ofperr
> -learn_check(const struct nx_action_learn *learn, const struct flow *flow)
> -{
> - struct cls_rule rule;
> - const void *p, *end;
> -
> - cls_rule_init_catchall(&rule, 0);
> + learn->idle_timeout = ntohs(nal->idle_timeout);
> + learn->hard_timeout = ntohs(nal->hard_timeout);
> + learn->priority = ntohs(nal->priority);
> + learn->cookie = ntohll(nal->cookie);
> + learn->flags = ntohs(nal->flags);
> + learn->table_id = nal->table_id;
> + learn->fin_idle_timeout = ntohs(nal->fin_idle_timeout);
> + learn->fin_hard_timeout = ntohs(nal->fin_hard_timeout);
>
> - if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
> - || learn->pad
> - || learn->table_id == 0xff) {
> + if (learn->flags & ~OFPFF_SEND_FLOW_REM || learn->table_id == 0xff) {
> return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - end = (char *) learn + ntohs(learn->len);
> - for (p = learn + 1; p != end; ) {
> + end = (char *) nal + ntohs(nal->len);
> + for (p = nal + 1; p != end; ) {
> + struct ofpact_learn_spec *spec;
> uint16_t header = ntohs(get_be16(&p));
> - int n_bits = header & NX_LEARN_N_BITS_MASK;
> - int src_type = header & NX_LEARN_SRC_MASK;
> - int dst_type = header & NX_LEARN_DST_MASK;
> -
> - enum ofperr error;
> - uint64_t value;
>
> if (!header) {
> break;
> }
>
> - error = learn_check_header(header, (char *) end - (char *) p);
> - if (error) {
> - return error;
> - }
> + spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
> + learn = ofpacts->l2;
> + learn->n_specs++;
>
> - /* Check the source. */
> - if (src_type == NX_LEARN_SRC_FIELD) {
> - struct mf_subfield src;
> + spec->src_type = header & NX_LEARN_SRC_MASK;
> + spec->dst_type = header & NX_LEARN_DST_MASK;
> + spec->n_bits = header & NX_LEARN_N_BITS_MASK;
>
> - get_subfield(n_bits, &p, &src);
> - error = mf_check_src(&src, flow);
> - if (error) {
> - return error;
> - }
> - value = 0;
> + /* Check for valid src and dst type combination. */
> + if (spec->dst_type == NX_LEARN_DST_MATCH ||
> + spec->dst_type == NX_LEARN_DST_LOAD ||
> + (spec->dst_type == NX_LEARN_DST_OUTPUT &&
> + spec->src_type == NX_LEARN_SRC_FIELD)) {
> + /* OK. */
> } else {
> - value = get_bits(n_bits, &p);
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - /* Check the destination. */
> - if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
> - struct mf_subfield dst;
> + /* Check that the arguments don't overrun the end of the action. */
> + if ((char *) end - (char *) p < learn_min_len(header)) {
> + return OFPERR_OFPBAC_BAD_LEN;
> + }
>
> - get_subfield(n_bits, &p, &dst);
> - error = (dst_type == NX_LEARN_DST_LOAD
> - ? mf_check_dst(&dst, &rule.flow)
> - : mf_check_src(&dst, &rule.flow));
> - if (error) {
> - return error;
> - }
> + /* Get the source. */
> + if (spec->src_type == NX_LEARN_SRC_FIELD) {
> + get_subfield(spec->n_bits, &p, &spec->src);
> + } else {
> + int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
>
> - if (dst_type == NX_LEARN_DST_MATCH
> - && src_type == NX_LEARN_SRC_IMMEDIATE) {
> - if (n_bits <= 64) {
> - mf_set_subfield(&dst, value, &rule);
> - } else {
> - /* We're only setting subfields to allow us to check
> - * prerequisites. No prerequisite depends on the value of
> - * a field that is wider than 64 bits. So just skip
> - * setting it entirely. */
> - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
> - }
> - }
> + bitwise_copy(p, p_bytes, 0,
> + &spec->src_imm, sizeof spec->src_imm, 0,
> + spec->n_bits);
> + p = (const uint8_t *) p + p_bytes;
> + }
> +
> + /* Get the destination. */
> + if (spec->dst_type == NX_LEARN_DST_MATCH ||
> + spec->dst_type == NX_LEARN_DST_LOAD) {
> + get_subfield(spec->n_bits, &p, &spec->dst);
> }
> }
> + ofpact_update_len(ofpacts, &learn->ofpact);
> +
> if (!is_all_zeros(p, (char *) end - (char *) p)) {
> return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
> @@ -196,98 +164,50 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
> return 0;
> }
>
> -void
> -learn_execute(const struct nx_action_learn *learn, const struct flow *flow,
> - struct ofputil_flow_mod *fm)
> +/* Checks that 'learn' is a valid action on 'flow'. Returns 0 if it is valid,
> + * otherwise an OFPERR_*. */
> +enum ofperr
> +learn_check(const struct ofpact_learn *learn, const struct flow *flow)
> {
> - const void *p, *end;
> - struct ofpbuf actions;
> -
> - cls_rule_init_catchall(&fm->cr, ntohs(learn->priority));
> - fm->cookie = htonll(0);
> - fm->cookie_mask = htonll(0);
> - fm->new_cookie = learn->cookie;
> - fm->table_id = learn->table_id;
> - fm->command = OFPFC_MODIFY_STRICT;
> - fm->idle_timeout = ntohs(learn->idle_timeout);
> - fm->hard_timeout = ntohs(learn->hard_timeout);
> - fm->buffer_id = UINT32_MAX;
> - fm->out_port = OFPP_NONE;
> - fm->flags = ntohs(learn->flags) & OFPFF_SEND_FLOW_REM;
> - fm->actions = NULL;
> - fm->n_actions = 0;
> -
> - ofpbuf_init(&actions, 64);
> -
> - if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
> - struct nx_action_fin_timeout *naft;
> -
> - naft = ofputil_put_NXAST_FIN_TIMEOUT(&actions);
> - naft->fin_idle_timeout = learn->fin_idle_timeout;
> - naft->fin_hard_timeout = learn->fin_hard_timeout;
> - }
> -
> - for (p = learn + 1, end = (char *) learn + ntohs(learn->len); p != end; ) {
> - uint16_t header = ntohs(get_be16(&p));
> - int n_bits = header & NX_LEARN_N_BITS_MASK;
> - int src_type = header & NX_LEARN_SRC_MASK;
> - int dst_type = header & NX_LEARN_DST_MASK;
> - union mf_subvalue value;
> -
> - struct mf_subfield dst;
> - int chunk, ofs;
> -
> - if (!header) {
> - break;
> - }
> -
> - if (src_type == NX_LEARN_SRC_FIELD) {
> - struct mf_subfield src;
> + const struct ofpact_learn_spec *spec;
> + struct cls_rule rule;
>
> - get_subfield(n_bits, &p, &src);
> - mf_read_subfield(&src, flow, &value);
> - } else {
> - int p_bytes = 2 * DIV_ROUND_UP(n_bits, 16);
> + cls_rule_init_catchall(&rule, 0);
> + for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
> + enum ofperr error;
>
> - memset(&value, 0, sizeof value);
> - bitwise_copy(p, p_bytes, 0,
> - &value, sizeof value, 0,
> - n_bits);
> - p = (const uint8_t *) p + p_bytes;
> + /* Check the source. */
> + if (spec->src_type == NX_LEARN_SRC_FIELD) {
> + error = mf_check_src(&spec->src, flow);
> + if (error) {
> + return error;
> + }
> }
>
> - switch (dst_type) {
> + /* Check the destination. */
> + switch (spec->dst_type) {
> case NX_LEARN_DST_MATCH:
> - get_subfield(n_bits, &p, &dst);
> - mf_write_subfield(&dst, &value, &fm->cr);
> + error = mf_check_src(&spec->dst, &rule.flow);
> + if (error) {
> + return error;
> + }
> +
> + mf_write_subfield(&spec->dst, &spec->src_imm, &rule);
> break;
>
> case NX_LEARN_DST_LOAD:
> - get_subfield(n_bits, &p, &dst);
> - for (ofs = 0; ofs < n_bits; ofs += chunk) {
> - struct nx_action_reg_load *load;
> -
> - chunk = MIN(n_bits - ofs, 64);
> -
> - load = ofputil_put_NXAST_REG_LOAD(&actions);
> - load->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs + ofs, chunk);
> - load->dst = htonl(dst.field->nxm_header);
> - bitwise_copy(&value, sizeof value, ofs,
> - &load->value, sizeof load->value, 0,
> - chunk);
> + error = mf_check_dst(&spec->dst, &rule.flow);
> + if (error) {
> + return error;
> }
> break;
>
> case NX_LEARN_DST_OUTPUT:
> - if (n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) {
> - ofputil_put_OFPAT10_OUTPUT(&actions)->port = value.be16[7];
> - }
> + /* Nothing to do. */
> break;
> }
> }
> -
> - fm->actions = ofpbuf_steal_data(&actions);
> - fm->n_actions = actions.size / sizeof(struct ofp_action_header);
> + return 0;
> }
>
> static void
> @@ -314,19 +234,150 @@ put_u32(struct ofpbuf *b, uint32_t x)
> put_be32(b, htonl(x));
> }
>
> -struct learn_spec {
> - int n_bits;
> +/* Converts 'learn' into a "struct nx_action_learn" and appends that action to
> + * 'ofpacts'. */
> +void
> +learn_to_openflow(const struct ofpact_learn *learn, struct ofpbuf *openflow)
> +{
> + const struct ofpact_learn_spec *spec;
> + struct nx_action_learn *nal;
> + size_t start_ofs;
> +
> + start_ofs = openflow->size;
> + nal = ofputil_put_NXAST_LEARN(openflow);
> + nal->idle_timeout = htons(learn->idle_timeout);
> + nal->hard_timeout = htons(learn->hard_timeout);
> + nal->fin_idle_timeout = htons(learn->fin_idle_timeout);
> + nal->fin_hard_timeout = htons(learn->fin_hard_timeout);
> + nal->priority = htons(learn->priority);
> + nal->cookie = htonll(learn->cookie);
> + nal->flags = htons(learn->flags);
> + nal->table_id = learn->table_id;
> +
> + for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
> + put_u16(openflow, spec->n_bits | spec->dst_type | spec->src_type);
> +
> + if (spec->src_type == NX_LEARN_SRC_FIELD) {
> + put_u32(openflow, spec->src.field->nxm_header);
> + put_u16(openflow, spec->src.ofs);
> + } else {
> + size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
> + uint8_t *bits = ofpbuf_put_zeros(openflow, n_dst_bytes);
> + bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0,
> + bits, n_dst_bytes, 0,
> + spec->n_bits);
> + }
> +
> + if (spec->dst_type == NX_LEARN_DST_MATCH ||
> + spec->dst_type == NX_LEARN_DST_LOAD) {
> + put_u32(openflow, spec->dst.field->nxm_header);
> + put_u16(openflow, spec->dst.ofs);
> + }
> + }
> +
> + if ((openflow->size - start_ofs) % 8) {
> + ofpbuf_put_zeros(openflow, 8 - (openflow->size - start_ofs) % 8);
> + }
> +
> + nal = ofpbuf_at_assert(openflow, start_ofs, sizeof *nal);
> + nal->len = htons(openflow->size - start_ofs);
> +}
> +
> +/* Composes 'fm' so that executing it will implement 'learn' given that the
> + * packet being processed has 'flow' as its flow.
> + *
> + * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize
> + * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the
> + * 'ofpacts' buffer.
> + *
> + * The caller has to actually execute 'fm'. */
> +void
> +learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
> + struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts)
> +{
> + const struct ofpact_learn_spec *spec;
>
> - int src_type;
> - struct mf_subfield src;
> - union mf_subvalue src_imm;
> + cls_rule_init_catchall(&fm->cr, learn->priority);
> + fm->cookie = htonll(0);
> + fm->cookie_mask = htonll(0);
> + fm->new_cookie = htonll(learn->cookie);
> + fm->table_id = learn->table_id;
> + fm->command = OFPFC_MODIFY_STRICT;
> + fm->idle_timeout = learn->idle_timeout;
> + fm->hard_timeout = learn->hard_timeout;
> + fm->buffer_id = UINT32_MAX;
> + fm->out_port = OFPP_NONE;
> + fm->flags = learn->flags;
> + fm->ofpacts = NULL;
> + fm->ofpacts_len = 0;
>
> - int dst_type;
> - struct mf_subfield dst;
> -};
> + if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
> + struct ofpact_fin_timeout *oft;
> +
> + oft = ofpact_put_FIN_TIMEOUT(ofpacts);
> + oft->fin_idle_timeout = learn->fin_idle_timeout;
> + oft->fin_hard_timeout = learn->fin_hard_timeout;
> + }
> +
> + for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
> + union mf_subvalue value;
> + int chunk, ofs;
> +
> + if (spec->src_type == NX_LEARN_SRC_FIELD) {
> + mf_read_subfield(&spec->src, flow, &value);
> + } else {
> + value = spec->src_imm;
> + }
> +
> + switch (spec->dst_type) {
> + case NX_LEARN_DST_MATCH:
> + mf_write_subfield(&spec->dst, &value, &fm->cr);
> + break;
> +
> + case NX_LEARN_DST_LOAD:
> + for (ofs = 0; ofs < spec->n_bits; ofs += chunk) {
> + struct ofpact_reg_load *load;
> + ovs_be64 value_be;
> +
> + chunk = MIN(spec->n_bits - ofs, 64);
> +
> + load = ofpact_put_REG_LOAD(ofpacts);
> + load->dst.field = spec->dst.field;
> + load->dst.ofs = spec->dst.ofs + ofs;
> + load->dst.n_bits = chunk;
> +
> + memset(&value_be, 0, sizeof value_be);
> + bitwise_copy(&value, sizeof value, ofs,
> + &value_be, sizeof value_be, 0,
> + chunk);
> + load->value = ntohll(value_be);
> + }
> + break;
> +
> + case NX_LEARN_DST_OUTPUT:
> + if (spec->n_bits <= 16
> + || is_all_zeros(value.u8, sizeof value - 2)) {
> + uint16_t port = ntohs(value.be16[7]);
> +
> + if (port < OFPP_MAX
> + || port == OFPP_IN_PORT
> + || port == OFPP_FLOOD
> + || port == OFPP_LOCAL
> + || port == OFPP_ALL) {
> + ofpact_put_OUTPUT(ofpacts)->port = port;
> + }
> + }
> + break;
> + }
> + }
> + ofpact_put_END(ofpacts);
> +
> + fm->ofpacts = ofpacts->data;
> + fm->ofpacts_len = ofpacts->size;
> +}
>
> static void
> -learn_parse_load_immediate(const char *s, struct learn_spec *spec)
> +learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
> {
> const char *full_s = s;
> const char *arrow = strstr(s, "->");
> @@ -377,9 +428,8 @@ learn_parse_load_immediate(const char *s, struct learn_spec *spec)
>
> static void
> learn_parse_spec(const char *orig, char *name, char *value,
> - struct learn_spec *spec)
> + struct ofpact_learn_spec *spec)
> {
> - memset(spec, 0, sizeof *spec);
> if (mf_from_name(name)) {
> const struct mf_field *dst = mf_from_name(name);
> union mf_value imm;
> @@ -428,17 +478,15 @@ learn_parse_spec(const char *orig, char *name, char *value,
> if (value[strcspn(value, "[-")] == '-') {
> learn_parse_load_immediate(value, spec);
> } else {
> - struct nx_action_reg_move move;
> + struct ofpact_reg_move move;
>
> nxm_parse_reg_move(&move, value);
>
> - spec->n_bits = ntohs(move.n_bits);
> + spec->n_bits = move.src.n_bits;
> spec->src_type = NX_LEARN_SRC_FIELD;
> - nxm_decode_discrete(&spec->src,
> - move.src, move.src_ofs, move.n_bits);
> + spec->src = move.src;
> spec->dst_type = NX_LEARN_DST_LOAD;
> - nxm_decode_discrete(&spec->dst,
> - move.dst, move.dst_ofs, move.n_bits);
> + spec->dst = move.dst;
> }
> } else if (!strcmp(name, "output")) {
> if (mf_parse_subfield(&spec->src, value)[0] != '\0') {
> @@ -455,8 +503,8 @@ learn_parse_spec(const char *orig, char *name, char *value,
> }
>
> /* Parses 'arg' as a set of arguments to the "learn" action and appends a
> - * matching NXAST_LEARN action to 'b'. The format parsed is described in
> - * ovs-ofctl(8).
> + * matching OFPACT_LEARN action to 'ofpacts'. ovs-ofctl(8) describes the
> + * format parsed.
> *
> * Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
> *
> @@ -466,29 +514,23 @@ learn_parse_spec(const char *orig, char *name, char *value,
> *
> * Modifies 'arg'. */
> void
> -learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
> +learn_parse(char *arg, const struct flow *flow, struct ofpbuf *ofpacts)
> {
> char *orig = xstrdup(arg);
> char *name, *value;
> - enum ofperr error;
> - size_t learn_ofs;
> - size_t len;
>
> - struct nx_action_learn *learn;
> + struct ofpact_learn *learn;
> struct cls_rule rule;
> + enum ofperr error;
>
> - learn_ofs = b->size;
> - learn = ofputil_put_NXAST_LEARN(b);
> - learn->idle_timeout = htons(OFP_FLOW_PERMANENT);
> - learn->hard_timeout = htons(OFP_FLOW_PERMANENT);
> - learn->priority = htons(OFP_DEFAULT_PRIORITY);
> - learn->cookie = htonll(0);
> - learn->flags = htons(0);
> + learn = ofpact_put_LEARN(ofpacts);
> + learn->idle_timeout = OFP_FLOW_PERMANENT;
> + learn->hard_timeout = OFP_FLOW_PERMANENT;
> + learn->priority = OFP_DEFAULT_PRIORITY;
> learn->table_id = 1;
>
> cls_rule_init_catchall(&rule, 0);
> while (ofputil_parse_key_value(&arg, &name, &value)) {
> - learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn);
> if (!strcmp(name, "table")) {
> learn->table_id = atoi(value);
> if (learn->table_id == 255) {
> @@ -496,73 +538,50 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
> orig);
> }
> } else if (!strcmp(name, "priority")) {
> - learn->priority = htons(atoi(value));
> + learn->priority = atoi(value);
> } else if (!strcmp(name, "idle_timeout")) {
> - learn->idle_timeout = htons(atoi(value));
> + learn->idle_timeout = atoi(value);
> } else if (!strcmp(name, "hard_timeout")) {
> - learn->hard_timeout = htons(atoi(value));
> + learn->hard_timeout = atoi(value);
> } else if (!strcmp(name, "fin_idle_timeout")) {
> - learn->fin_idle_timeout = htons(atoi(value));
> + learn->fin_idle_timeout = atoi(value);
> } else if (!strcmp(name, "fin_hard_timeout")) {
> - learn->fin_hard_timeout = htons(atoi(value));
> + learn->fin_hard_timeout = atoi(value);
> } else if (!strcmp(name, "cookie")) {
> - learn->cookie = htonll(strtoull(value, NULL, 0));
> + learn->cookie = strtoull(value, NULL, 0);
> } else {
> - struct learn_spec spec;
> + struct ofpact_learn_spec *spec;
> +
> + spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
> + learn = ofpacts->l2;
> + learn->n_specs++;
>
> - learn_parse_spec(orig, name, value, &spec);
> + learn_parse_spec(orig, name, value, spec);
>
> /* Check prerequisites. */
> - if (spec.src_type == NX_LEARN_SRC_FIELD
> - && flow && !mf_are_prereqs_ok(spec.src.field, flow)) {
> + if (spec->src_type == NX_LEARN_SRC_FIELD
> + && flow && !mf_are_prereqs_ok(spec->src.field, flow)) {
> ovs_fatal(0, "%s: cannot specify source field %s because "
> "prerequisites are not satisfied",
> - orig, spec.src.field->name);
> + orig, spec->src.field->name);
> }
> - if ((spec.dst_type == NX_LEARN_DST_MATCH
> - || spec.dst_type == NX_LEARN_DST_LOAD)
> - && !mf_are_prereqs_ok(spec.dst.field, &rule.flow)) {
> + if ((spec->dst_type == NX_LEARN_DST_MATCH
> + || spec->dst_type == NX_LEARN_DST_LOAD)
> + && !mf_are_prereqs_ok(spec->dst.field, &rule.flow)) {
> ovs_fatal(0, "%s: cannot specify destination field %s because "
> "prerequisites are not satisfied",
> - orig, spec.dst.field->name);
> + orig, spec->dst.field->name);
> }
>
> /* Update 'rule' to allow for satisfying destination
> * prerequisites. */
> - if (spec.src_type == NX_LEARN_SRC_IMMEDIATE
> - && spec.dst_type == NX_LEARN_DST_MATCH) {
> - mf_write_subfield(&spec.dst, &spec.src_imm, &rule);
> - }
> -
> - /* Output the flow_mod_spec. */
> - put_u16(b, spec.n_bits | spec.src_type | spec.dst_type);
> - if (spec.src_type == NX_LEARN_SRC_IMMEDIATE) {
> - int n_bytes = DIV_ROUND_UP(spec.n_bits, 16) * 2;
> - int ofs = sizeof spec.src_imm - n_bytes;
> - ofpbuf_put(b, &spec.src_imm.u8[ofs], n_bytes);
> - } else {
> - put_u32(b, spec.src.field->nxm_header);
> - put_u16(b, spec.src.ofs);
> - }
> - if (spec.dst_type == NX_LEARN_DST_MATCH ||
> - spec.dst_type == NX_LEARN_DST_LOAD) {
> - put_u32(b, spec.dst.field->nxm_header);
> - put_u16(b, spec.dst.ofs);
> - } else {
> - assert(spec.dst_type == NX_LEARN_DST_OUTPUT);
> + if (spec->src_type == NX_LEARN_SRC_IMMEDIATE
> + && spec->dst_type == NX_LEARN_DST_MATCH) {
> + mf_write_subfield(&spec->dst, &spec->src_imm, &rule);
> }
> }
> }
> -
> - put_u16(b, 0);
> -
> - len = b->size - learn_ofs;
> - if (len % 8) {
> - ofpbuf_put_zeros(b, 8 - len % 8);
> - }
> -
> - learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn);
> - learn->len = htons(b->size - learn_ofs);
> + ofpact_update_len(ofpacts, &learn->ofpact);
>
> /* In theory the above should have caught any errors, but... */
> if (flow) {
> @@ -574,169 +593,106 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
> free(orig);
> }
>
> +static void
> +format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(subvalue->u8); i++) {
> + if (subvalue->u8[i]) {
> + ds_put_format(s, "0x%"PRIx8, subvalue->u8[i]);
> + for (i++; i < ARRAY_SIZE(subvalue->u8); i++) {
> + ds_put_format(s, "%02"PRIx8, subvalue->u8[i]);
> + }
> + return;
> + }
> + }
> + ds_put_char(s, '0');
> +}
> +
> +/* Appends a description of 'learn' to 's', in the format that ovs-ofctl(8)
> + * describes. */
> void
> -learn_format(const struct nx_action_learn *learn, struct ds *s)
> +learn_format(const struct ofpact_learn *learn, struct ds *s)
> {
> + const struct ofpact_learn_spec *spec;
> struct cls_rule rule;
> - const void *p, *end;
>
> cls_rule_init_catchall(&rule, 0);
>
> ds_put_format(s, "learn(table=%"PRIu8, learn->table_id);
> - if (learn->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
> - ds_put_format(s, ",idle_timeout=%"PRIu16, ntohs(learn->idle_timeout));
> + if (learn->idle_timeout != OFP_FLOW_PERMANENT) {
> + ds_put_format(s, ",idle_timeout=%"PRIu16, learn->idle_timeout);
> }
> - if (learn->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
> - ds_put_format(s, ",hard_timeout=%"PRIu16, ntohs(learn->hard_timeout));
> + if (learn->hard_timeout != OFP_FLOW_PERMANENT) {
> + ds_put_format(s, ",hard_timeout=%"PRIu16, learn->hard_timeout);
> }
> if (learn->fin_idle_timeout) {
> - ds_put_format(s, ",fin_idle_timeout=%"PRIu16,
> - ntohs(learn->fin_idle_timeout));
> + ds_put_format(s, ",fin_idle_timeout=%"PRIu16, learn->fin_idle_timeout);
> }
> if (learn->fin_hard_timeout) {
> - ds_put_format(s, ",fin_hard_timeout=%"PRIu16,
> - ntohs(learn->fin_hard_timeout));
> + ds_put_format(s, ",fin_hard_timeout=%"PRIu16, learn->fin_hard_timeout);
> }
> - if (learn->priority != htons(OFP_DEFAULT_PRIORITY)) {
> - ds_put_format(s, ",priority=%"PRIu16, ntohs(learn->priority));
> + if (learn->priority != OFP_DEFAULT_PRIORITY) {
> + ds_put_format(s, ",priority=%"PRIu16, learn->priority);
> }
> - if (learn->flags & htons(OFPFF_SEND_FLOW_REM)) {
> + if (learn->flags & OFPFF_SEND_FLOW_REM) {
> ds_put_cstr(s, ",OFPFF_SEND_FLOW_REM");
> }
> - if (learn->flags & htons(~OFPFF_SEND_FLOW_REM)) {
> - ds_put_format(s, ",***flags=%"PRIu16"***",
> - ntohs(learn->flags) & ~OFPFF_SEND_FLOW_REM);
> + if (learn->cookie != 0) {
> + ds_put_format(s, ",cookie=%#"PRIx64, learn->cookie);
> }
> - if (learn->cookie != htonll(0)) {
> - ds_put_format(s, ",cookie=0x%"PRIx64, ntohll(learn->cookie));
> - }
> - if (learn->pad != 0) {
> - ds_put_cstr(s, ",***nonzero pad***");
> - }
> -
> - end = (char *) learn + ntohs(learn->len);
> - for (p = learn + 1; p != end; ) {
> - uint16_t header = ntohs(get_be16(&p));
> - int n_bits = header & NX_LEARN_N_BITS_MASK;
> -
> - int src_type = header & NX_LEARN_SRC_MASK;
> - struct mf_subfield src;
> - const uint8_t *src_value;
> - int src_value_bytes;
> -
> - int dst_type = header & NX_LEARN_DST_MASK;
> - struct mf_subfield dst;
> -
> - enum ofperr error;
> - int i;
> -
> - if (!header) {
> - break;
> - }
> -
> - error = learn_check_header(header, (char *) end - (char *) p);
> - if (error == OFPERR_OFPBAC_BAD_ARGUMENT) {
> - ds_put_format(s, ",***bad flow_mod_spec header %"PRIx16"***)",
> - header);
> - return;
> - } else if (error == OFPERR_OFPBAC_BAD_LEN) {
> - ds_put_format(s, ",***flow_mod_spec at offset %td is %u bytes "
> - "long but only %td bytes are left***)",
> - (char *) p - (char *) (learn + 1) - 2,
> - learn_min_len(header) + 2,
> - (char *) end - (char *) p + 2);
> - return;
> - }
> - assert(!error);
> -
> - /* Get the source. */
> - if (src_type == NX_LEARN_SRC_FIELD) {
> - get_subfield(n_bits, &p, &src);
> - src_value_bytes = 0;
> - src_value = NULL;
> - } else {
> - src.field = NULL;
> - src.ofs = 0;
> - src.n_bits = 0;
> - src_value_bytes = 2 * DIV_ROUND_UP(n_bits, 16);
> - src_value = p;
> - p = (const void *) ((const uint8_t *) p + src_value_bytes);
> - }
> -
> - /* Get the destination. */
> - if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
> - get_subfield(n_bits, &p, &dst);
> - } else {
> - dst.field = NULL;
> - dst.ofs = 0;
> - dst.n_bits = 0;
> - }
>
> + for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
> ds_put_char(s, ',');
>
> - switch (src_type | dst_type) {
> + switch (spec->src_type | spec->dst_type) {
> case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH:
> - if (dst.field && dst.ofs == 0 && n_bits == dst.field->n_bits) {
> + if (spec->dst.ofs == 0
> + && spec->dst.n_bits == spec->dst.field->n_bits) {
> union mf_value value;
> - uint8_t *bytes = (uint8_t *) &value;
> -
> - if (src_value_bytes > dst.field->n_bytes) {
> - /* The destination field is an odd number of bytes, which
> - * got rounded up to a multiple of 2 to be put into the
> - * learning action. Skip over the leading byte, which
> - * should be zero anyway. Otherwise the memcpy() below
> - * will overrun the start of 'value'. */
> - int diff = src_value_bytes - dst.field->n_bytes;
> - src_value += diff;
> - src_value_bytes -= diff;
> - }
>
> memset(&value, 0, sizeof value);
> - memcpy(&bytes[dst.field->n_bytes - src_value_bytes],
> - src_value, src_value_bytes);
> - ds_put_format(s, "%s=", dst.field->name);
> - mf_format(dst.field, &value, NULL, s);
> + bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0,
> + &value, spec->dst.field->n_bytes, 0,
> + spec->dst.field->n_bits);
> + ds_put_format(s, "%s=", spec->dst.field->name);
> + mf_format(spec->dst.field, &value, NULL, s);
> } else {
> - mf_format_subfield(&dst, s);
> - ds_put_cstr(s, "=0x");
> - for (i = 0; i < src_value_bytes; i++) {
> - ds_put_format(s, "%02"PRIx8, src_value[i]);
> - }
> + mf_format_subfield(&spec->dst, s);
> + ds_put_char(s, '=');
> + format_subvalue(&spec->src_imm, s);
> }
> break;
>
> case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH:
> - mf_format_subfield(&dst, s);
> - if (src.field != dst.field || src.ofs != dst.ofs) {
> + mf_format_subfield(&spec->dst, s);
> + if (spec->src.field != spec->dst.field ||
> + spec->src.ofs != spec->dst.ofs) {
> ds_put_char(s, '=');
> - mf_format_subfield(&src, s);
> + mf_format_subfield(&spec->src, s);
> }
> break;
>
> case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD:
> - ds_put_cstr(s, "load:0x");
> - for (i = 0; i < src_value_bytes; i++) {
> - ds_put_format(s, "%02"PRIx8, src_value[i]);
> - }
> + ds_put_format(s, "load:");
> + format_subvalue(&spec->src_imm, s);
> ds_put_cstr(s, "->");
> - mf_format_subfield(&dst, s);
> + mf_format_subfield(&spec->dst, s);
> break;
>
> case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD:
> ds_put_cstr(s, "load:");
> - mf_format_subfield(&src, s);
> + mf_format_subfield(&spec->src, s);
> ds_put_cstr(s, "->");
> - mf_format_subfield(&dst, s);
> + mf_format_subfield(&spec->dst, s);
> break;
>
> case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT:
> ds_put_cstr(s, "output:");
> - mf_format_subfield(&src, s);
> + mf_format_subfield(&spec->src, s);
> break;
> }
> }
> - if (!is_all_zeros(p, (char *) end - (char *) p)) {
> - ds_put_cstr(s, ",***nonzero trailer***");
> - }
> ds_put_char(s, ')');
> }
> diff --git a/lib/learn.h b/lib/learn.h
> index 2859172..e7fe390 100644
> --- a/lib/learn.h
> +++ b/lib/learn.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2011 Nicira, Inc.
> + * Copyright (c) 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -22,6 +22,7 @@
> struct ds;
> struct flow;
> struct ofpbuf;
> +struct ofpact_learn;
> struct ofputil_flow_mod;
> struct nx_action_learn;
>
> @@ -30,11 +31,15 @@ struct nx_action_learn;
> * See include/openflow/nicira-ext.h for NXAST_LEARN specification.
> */
>
> -enum ofperr learn_check(const struct nx_action_learn *, const struct flow *);
> -void learn_execute(const struct nx_action_learn *, const struct flow *,
> - struct ofputil_flow_mod *);
> +enum ofperr learn_from_openflow(const struct nx_action_learn *,
> + struct ofpbuf *ofpacts);
> +enum ofperr learn_check(const struct ofpact_learn *, const struct flow *);
> +void learn_to_openflow(const struct ofpact_learn *, struct ofpbuf *openflow);
>
> -void learn_parse(struct ofpbuf *, char *, const struct flow *);
> -void learn_format(const struct nx_action_learn *, struct ds *);
> +void learn_execute(const struct ofpact_learn *, const struct flow *,
> + struct ofputil_flow_mod *, struct ofpbuf *ofpacts);
> +
> +void learn_parse(char *, const struct flow *, struct ofpbuf *ofpacts);
> +void learn_format(const struct ofpact_learn *, struct ds *);
>
> #endif /* learn.h */
> diff --git a/lib/learning-switch.c b/lib/learning-switch.c
> index 6b74f82..916abf3 100644
> --- a/lib/learning-switch.c
> +++ b/lib/learning-switch.c
> @@ -29,6 +29,7 @@
> #include "hmap.h"
> #include "mac-learning.h"
> #include "ofpbuf.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-parse.h"
> #include "ofp-print.h"
> @@ -56,6 +57,7 @@ struct lswitch {
> * Otherwise, the switch processes every packet. */
> int max_idle;
>
> + enum ofputil_protocol protocol;
> unsigned long long int datapath_id;
> time_t last_features_request;
> struct mac_learning *ml; /* NULL to act as hub instead of switch. */
> @@ -81,7 +83,7 @@ static void send_features_request(struct lswitch *, struct rconn *);
> static enum ofperr process_switch_features(struct lswitch *,
> struct ofp_switch_features *);
> static void process_packet_in(struct lswitch *, struct rconn *,
> - const struct ofp_packet_in *);
> + const struct ofp_header *);
> static void process_echo_request(struct lswitch *, struct rconn *,
> const struct ofp_header *);
>
> @@ -92,6 +94,7 @@ static void process_echo_request(struct lswitch *, struct rconn *,
> struct lswitch *
> lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
> {
> + enum ofputil_protocol protocol;
> struct lswitch *sw;
>
> sw = xzalloc(sizeof *sw);
> @@ -139,18 +142,13 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
> sw->queued = rconn_packet_counter_create();
> send_features_request(sw, rconn);
>
> + protocol = ofputil_protocol_from_ofp_version(rconn_get_version(rconn));
> if (cfg->default_flows) {
> enum ofputil_protocol usable_protocols;
> - enum ofputil_protocol protocol;
> struct ofpbuf *msg = NULL;
> - int ofp_version;
> int error = 0;
> size_t i;
>
> - /* Figure out the initial protocol on the connection. */
> - ofp_version = rconn_get_version(rconn);
> - protocol = ofputil_protocol_from_ofp_version(ofp_version);
> -
> /* If the initial protocol isn't good enough for default_flows, then
> * pick one that will work and encode messages to set up that
> * protocol.
> @@ -181,6 +179,7 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
> rconn_get_name(rconn), strerror(error));
> }
> }
> + sw->protocol = protocol;
>
> return sw;
> }
> @@ -250,6 +249,7 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
> break;
>
> case OFPUTIL_OFPT_PACKET_IN:
> + case OFPUTIL_NXT_PACKET_IN:
> process_packet_in(sw, rconn, msg->data);
> break;
>
> @@ -292,7 +292,6 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
> 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_NXT_FLOW_AGE:
> @@ -439,67 +438,58 @@ get_queue_id(const struct lswitch *sw, uint16_t in_port)
>
> static void
> process_packet_in(struct lswitch *sw, struct rconn *rconn,
> - const struct ofp_packet_in *opi)
> + const struct ofp_header *oh)
> {
> - uint16_t in_port = ntohs(opi->in_port);
> + struct ofputil_packet_in pi;
> uint32_t queue_id;
> uint16_t out_port;
>
> - struct ofp_action_header actions[2];
> - size_t actions_len;
> + uint64_t ofpacts_stub[64 / 8];
> + struct ofpbuf ofpacts;
>
> struct ofputil_packet_out po;
> + enum ofperr error;
>
> - size_t pkt_ofs, pkt_len;
> struct ofpbuf pkt;
> struct flow flow;
>
> + error = ofputil_decode_packet_in(&pi, oh);
> + if (error) {
> + VLOG_WARN_RL(&rl, "failed to decode packet-in: %s",
> + ofperr_to_string(error));
> + return;
> + }
> +
> /* Ignore packets sent via output to OFPP_CONTROLLER. This library never
> * uses such an action. You never know what experiments might be going on,
> * though, and it seems best not to interfere with them. */
> - if (opi->reason != OFPR_NO_MATCH) {
> + if (pi.reason != OFPR_NO_MATCH) {
> return;
> }
>
> /* Extract flow data from 'opi' into 'flow'. */
> - pkt_ofs = offsetof(struct ofp_packet_in, data);
> - pkt_len = ntohs(opi->header.length) - pkt_ofs;
> - ofpbuf_use_const(&pkt, opi->data, pkt_len);
> - flow_extract(&pkt, 0, 0, in_port, &flow);
> + ofpbuf_use_const(&pkt, pi.packet, pi.packet_len);
> + flow_extract(&pkt, 0, pi.fmd.tun_id, pi.fmd.in_port, &flow);
>
> /* Choose output port. */
> out_port = lswitch_choose_destination(sw, &flow);
>
> /* Make actions. */
> - queue_id = get_queue_id(sw, in_port);
> + queue_id = get_queue_id(sw, pi.fmd.in_port);
> + ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
> if (out_port == OFPP_NONE) {
> - actions_len = 0;
> + /* No actions. */
> } else if (queue_id == UINT32_MAX || out_port >= OFPP_MAX) {
> - struct ofp_action_output oao;
> -
> - memset(&oao, 0, sizeof oao);
> - oao.type = htons(OFPAT10_OUTPUT);
> - oao.len = htons(sizeof oao);
> - oao.port = htons(out_port);
> -
> - memcpy(actions, &oao, sizeof oao);
> - actions_len = sizeof oao;
> + ofpact_put_OUTPUT(&ofpacts)->port = out_port;
> } else {
> - struct ofp_action_enqueue oae;
> -
> - memset(&oae, 0, sizeof oae);
> - oae.type = htons(OFPAT10_ENQUEUE);
> - oae.len = htons(sizeof oae);
> - oae.port = htons(out_port);
> - oae.queue_id = htonl(queue_id);
> -
> - memcpy(actions, &oae, sizeof oae);
> - actions_len = sizeof oae;
> + struct ofpact_enqueue *enqueue = ofpact_put_ENQUEUE(&ofpacts);
> + enqueue->port = out_port;
> + enqueue->queue = queue_id;
> }
> - assert(actions_len <= sizeof actions);
> + ofpact_put_END(&ofpacts);
>
> /* Prepare packet_out in case we need one. */
> - po.buffer_id = ntohl(opi->buffer_id);
> + po.buffer_id = pi.buffer_id;
> if (po.buffer_id == UINT32_MAX) {
> po.packet = pkt.data;
> po.packet_len = pkt.size;
> @@ -507,31 +497,38 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn,
> po.packet = NULL;
> po.packet_len = 0;
> }
> - po.in_port = in_port;
> - po.actions = (union ofp_action *) actions;
> - po.n_actions = actions_len / sizeof *actions;
> + po.in_port = pi.fmd.in_port;
> + po.ofpacts = ofpacts.data;
> + po.ofpacts_len = ofpacts.size;
>
> /* Send the packet, and possibly the whole flow, to the output port. */
> if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
> + struct ofputil_flow_mod fm;
> struct ofpbuf *buffer;
> - struct cls_rule rule;
>
> /* The output port is known, or we always flood everything, so add a
> * new flow. */
> - cls_rule_init(&flow, &sw->wc, 0, &rule);
> - buffer = make_add_flow(&rule, ntohl(opi->buffer_id),
> - sw->max_idle, actions_len);
> - ofpbuf_put(buffer, actions, actions_len);
> + memset(&fm, 0, sizeof fm);
> + cls_rule_init(&flow, &sw->wc, 0, &fm.cr);
> + fm.table_id = 0xff;
> + fm.command = OFPFC_ADD;
> + fm.idle_timeout = sw->max_idle;
> + fm.buffer_id = pi.buffer_id;
> + fm.out_port = OFPP_NONE;
> + fm.ofpacts = ofpacts.data;
> + fm.ofpacts_len = ofpacts.size;
> + buffer = ofputil_encode_flow_mod(&fm, sw->protocol);
> +
> queue_tx(sw, rconn, buffer);
>
> /* If the switch didn't buffer the packet, we need to send a copy. */
> - if (ntohl(opi->buffer_id) == UINT32_MAX && actions_len > 0) {
> + if (pi.buffer_id == UINT32_MAX && out_port != OFPP_NONE) {
> queue_tx(sw, rconn, ofputil_encode_packet_out(&po));
> }
> } else {
> /* We don't know that MAC, or we don't set up flows. Send along the
> * packet without setting up a flow. */
> - if (ntohl(opi->buffer_id) != UINT32_MAX || actions_len > 0) {
> + if (pi.buffer_id != UINT32_MAX || out_port != OFPP_NONE) {
> queue_tx(sw, rconn, ofputil_encode_packet_out(&po));
> }
> }
> diff --git a/lib/multipath.c b/lib/multipath.c
> index 8d93211..c0a5723 100644
> --- a/lib/multipath.c
> +++ b/lib/multipath.c
> @@ -22,8 +22,8 @@
> #include <sys/types.h>
> #include <netinet/in.h>
> #include "dynamic-string.h"
> -#include "meta-flow.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "openflow/nicira-ext.h"
> @@ -34,37 +34,67 @@ VLOG_DEFINE_THIS_MODULE(multipath);
>
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
> -/* multipath_check(). */
> +/* Converts 'nam' into 'mp'. Returns 0 if successful, otherwise an
> + * OFPERR_*. */
> enum ofperr
> -multipath_check(const struct nx_action_multipath *mp, const struct flow *flow)
> +multipath_from_openflow(const struct nx_action_multipath *nam,
> + struct ofpact_multipath *mp)
> {
> - uint32_t n_links = ntohs(mp->max_link) + 1;
> + uint32_t n_links = ntohs(nam->max_link) + 1;
> size_t min_n_bits = log_2_ceil(n_links);
> - struct mf_subfield dst;
> - enum ofperr error;
>
> - nxm_decode(&dst, mp->dst, mp->ofs_nbits);
> - error = mf_check_dst(&dst, flow);
> - if (error) {
> - return error;
> - }
> -
> - if (!flow_hash_fields_valid(ntohs(mp->fields))) {
> - VLOG_WARN_RL(&rl, "unsupported fields %"PRIu16, ntohs(mp->fields));
> - } else if (mp->algorithm != htons(NX_MP_ALG_MODULO_N)
> - && mp->algorithm != htons(NX_MP_ALG_HASH_THRESHOLD)
> - && mp->algorithm != htons(NX_MP_ALG_HRW)
> - && mp->algorithm != htons(NX_MP_ALG_ITER_HASH)) {
> - VLOG_WARN_RL(&rl, "unsupported algorithm %"PRIu16,
> - ntohs(mp->algorithm));
> - } else if (dst.n_bits < min_n_bits) {
> + ofpact_init_MULTIPATH(mp);
> + mp->fields = ntohs(nam->fields);
> + mp->basis = ntohs(nam->basis);
> + mp->algorithm = ntohs(nam->algorithm);
> + mp->max_link = ntohs(nam->max_link);
> + mp->arg = ntohl(nam->arg);
> + mp->dst.field = mf_from_nxm_header(ntohl(nam->dst));
> + mp->dst.ofs = nxm_decode_ofs(nam->ofs_nbits);
> + mp->dst.n_bits = nxm_decode_n_bits(nam->ofs_nbits);
> +
> + if (!flow_hash_fields_valid(mp->fields)) {
> + VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields);
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + } else if (mp->algorithm != NX_MP_ALG_MODULO_N
> + && mp->algorithm != NX_MP_ALG_HASH_THRESHOLD
> + && mp->algorithm != NX_MP_ALG_HRW
> + && mp->algorithm != NX_MP_ALG_ITER_HASH) {
> + VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) mp->algorithm);
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + } else if (mp->dst.n_bits < min_n_bits) {
> VLOG_WARN_RL(&rl, "multipath action requires at least %zu bits for "
> "%"PRIu32" links", min_n_bits, n_links);
> - } else {
> - return 0;
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - return OFPERR_OFPBAC_BAD_ARGUMENT;
> + return multipath_check(mp, NULL);
> +}
> +
> +/* Checks that 'mp' is valid on flow. Returns 0 if it is valid, otherwise an
> + * OFPERR_*. */
> +enum ofperr
> +multipath_check(const struct ofpact_multipath *mp,
> + const struct flow *flow)
> +{
> + return mf_check_dst(&mp->dst, flow);
> +}
> +
> +/* Converts 'mp' into an OpenFlow NXAST_MULTIPATH action, which it appends to
> + * 'openflow'. */
> +void
> +multipath_to_openflow(const struct ofpact_multipath *mp,
> + struct ofpbuf *openflow)
> +{
> + struct nx_action_multipath *nam = ofputil_put_NXAST_MULTIPATH(openflow);
> +
> + nam->fields = htons(mp->fields);
> + nam->basis = htons(mp->basis);
> + nam->algorithm = htons(mp->algorithm);
> + nam->max_link = htons(mp->max_link);
> + nam->arg = htonl(mp->arg);
> + nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits);
> + nam->dst = htonl(mp->dst.field->nxm_header);
> }
>
> /* multipath_execute(). */
> @@ -72,19 +102,17 @@ multipath_check(const struct nx_action_multipath *mp, const struct flow *flow)
> static uint16_t multipath_algorithm(uint32_t hash, enum nx_mp_algorithm,
> unsigned int n_links, unsigned int arg);
>
> +/* Executes 'mp' based on the current contents of 'flow', writing the results
> + * back into 'flow'. */
> void
> -multipath_execute(const struct nx_action_multipath *mp, struct flow *flow)
> +multipath_execute(const struct ofpact_multipath *mp, struct flow *flow)
> {
> /* Calculate value to store. */
> - uint32_t hash = flow_hash_fields(flow, ntohs(mp->fields),
> - ntohs(mp->basis));
> - uint16_t link = multipath_algorithm(hash, ntohs(mp->algorithm),
> - ntohs(mp->max_link) + 1,
> - ntohl(mp->arg));
> - struct mf_subfield dst;
> -
> - nxm_decode(&dst, mp->dst, mp->ofs_nbits);
> - mf_set_subfield_value(&dst, link, flow);
> + uint32_t hash = flow_hash_fields(flow, mp->fields, mp->basis);
> + uint16_t link = multipath_algorithm(hash, mp->algorithm,
> + mp->max_link + 1, mp->arg);
> +
> + nxm_reg_load(&mp->dst, link, flow);
> }
>
> static uint16_t
> @@ -162,15 +190,17 @@ multipath_algorithm(uint32_t hash, enum nx_mp_algorithm algorithm,
> NOT_REACHED();
> }
>
> -/* multipath_parse(). */
> -
> +/* Parses 's_' as a set of arguments to the "multipath" action and initializes
> + * 'mp' accordingly. ovs-ofctl(8) describes the format parsed.
> + *
> + * Prints an error on stderr and aborts the program if 's_' syntax is
> + * invalid. */
> void
> -multipath_parse(struct nx_action_multipath *mp, const char *s_)
> +multipath_parse(struct ofpact_multipath *mp, const char *s_)
> {
> char *s = xstrdup(s_);
> char *save_ptr = NULL;
> - char *fields, *basis, *algorithm, *n_links_str, *arg, *dst_s;
> - struct mf_subfield dst;
> + char *fields, *basis, *algorithm, *n_links_str, *arg, *dst;
> int n_links;
>
> fields = strtok_r(s, ", ", &save_ptr);
> @@ -178,28 +208,28 @@ multipath_parse(struct nx_action_multipath *mp, const char *s_)
> algorithm = strtok_r(NULL, ", ", &save_ptr);
> n_links_str = strtok_r(NULL, ", ", &save_ptr);
> arg = strtok_r(NULL, ", ", &save_ptr);
> - dst_s = strtok_r(NULL, ", ", &save_ptr);
> - if (!dst_s) {
> + dst = strtok_r(NULL, ", ", &save_ptr);
> + if (!dst) {
> ovs_fatal(0, "%s: not enough arguments to multipath action", s_);
> }
>
> - ofputil_init_NXAST_MULTIPATH(mp);
> + ofpact_init_MULTIPATH(mp);
> if (!strcasecmp(fields, "eth_src")) {
> - mp->fields = htons(NX_HASH_FIELDS_ETH_SRC);
> + mp->fields = NX_HASH_FIELDS_ETH_SRC;
> } else if (!strcasecmp(fields, "symmetric_l4")) {
> - mp->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4);
> + mp->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
> } else {
> ovs_fatal(0, "%s: unknown fields `%s'", s_, fields);
> }
> - mp->basis = htons(atoi(basis));
> + mp->basis = atoi(basis);
> if (!strcasecmp(algorithm, "modulo_n")) {
> - mp->algorithm = htons(NX_MP_ALG_MODULO_N);
> + mp->algorithm = NX_MP_ALG_MODULO_N;
> } else if (!strcasecmp(algorithm, "hash_threshold")) {
> - mp->algorithm = htons(NX_MP_ALG_HASH_THRESHOLD);
> + mp->algorithm = NX_MP_ALG_HASH_THRESHOLD;
> } else if (!strcasecmp(algorithm, "hrw")) {
> - mp->algorithm = htons(NX_MP_ALG_HRW);
> + mp->algorithm = NX_MP_ALG_HRW;
> } else if (!strcasecmp(algorithm, "iter_hash")) {
> - mp->algorithm = htons(NX_MP_ALG_ITER_HASH);
> + mp->algorithm = NX_MP_ALG_ITER_HASH;
> } else {
> ovs_fatal(0, "%s: unknown algorithm `%s'", s_, algorithm);
> }
> @@ -208,34 +238,29 @@ multipath_parse(struct nx_action_multipath *mp, const char *s_)
> ovs_fatal(0, "%s: n_links %d is not in valid range 1 to 65536",
> s_, n_links);
> }
> - mp->max_link = htons(n_links - 1);
> - mp->arg = htonl(atoi(arg));
> + mp->max_link = n_links - 1;
> + mp->arg = atoi(arg);
>
> - mf_parse_subfield(&dst, dst_s);
> - if (dst.n_bits < 16 && n_links > (1u << dst.n_bits)) {
> + mf_parse_subfield(&mp->dst, dst);
> + if (mp->dst.n_bits < 16 && n_links > (1u << mp->dst.n_bits)) {
> ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
> "less than specified n_links %d",
> - s_, dst.n_bits, 1u << dst.n_bits, n_links);
> + s_, mp->dst.n_bits, 1u << mp->dst.n_bits, n_links);
> }
> - mp->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
> - mp->dst = htonl(dst.field->nxm_header);
>
> free(s);
> }
>
> +/* Appends a description of 'mp' to 's', in the format that ovs-ofctl(8)
> + * describes. */
> void
> -multipath_format(const struct nx_action_multipath *mp, struct ds *s)
> +multipath_format(const struct ofpact_multipath *mp, struct ds *s)
> {
> const char *fields, *algorithm;
>
> - uint16_t mp_fields = ntohs(mp->fields);
> - uint16_t mp_algorithm = ntohs(mp->algorithm);
> -
> - struct mf_subfield dst;
> -
> - fields = flow_hash_fields_to_str(mp_fields);
> + fields = flow_hash_fields_to_str(mp->fields);
>
> - switch ((enum nx_mp_algorithm) mp_algorithm) {
> + switch (mp->algorithm) {
> case NX_MP_ALG_MODULO_N:
> algorithm = "modulo_n";
> break;
> @@ -253,9 +278,8 @@ multipath_format(const struct nx_action_multipath *mp, struct ds *s)
> }
>
> ds_put_format(s, "multipath(%s,%"PRIu16",%s,%d,%"PRIu16",",
> - fields, ntohs(mp->basis), algorithm, ntohs(mp->max_link) + 1,
> - ntohl(mp->arg));
> - nxm_decode(&dst, mp->dst, mp->ofs_nbits);
> - mf_format_subfield(&dst, s);
> + fields, mp->basis, algorithm, mp->max_link + 1,
> + mp->arg);
> + mf_format_subfield(&mp->dst, s);
> ds_put_char(s, ')');
> }
> diff --git a/lib/multipath.h b/lib/multipath.h
> index 2cd646c..4e45d6c 100644
> --- a/lib/multipath.h
> +++ b/lib/multipath.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2010, 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -23,18 +23,24 @@
> struct ds;
> struct flow;
> struct nx_action_multipath;
> -struct nx_action_reg_move;
> +struct ofpact_multipath;
> +struct ofpbuf;
>
> /* NXAST_MULTIPATH helper functions.
> *
> * See include/openflow/nicira-ext.h for NXAST_MULTIPATH specification.
> */
>
> -enum ofperr multipath_check(const struct nx_action_multipath *,
> +enum ofperr multipath_from_openflow(const struct nx_action_multipath *,
> + struct ofpact_multipath *);
> +enum ofperr multipath_check(const struct ofpact_multipath *,
> const struct flow *);
> -void multipath_execute(const struct nx_action_multipath *, struct flow *);
> +void multipath_to_openflow(const struct ofpact_multipath *,
> + struct ofpbuf *openflow);
>
> -void multipath_parse(struct nx_action_multipath *, const char *);
> -void multipath_format(const struct nx_action_multipath *, struct ds *);
> +void multipath_execute(const struct ofpact_multipath *, struct flow *);
> +
> +void multipath_parse(struct ofpact_multipath *, const char *);
> +void multipath_format(const struct ofpact_multipath *, struct ds *);
>
> #endif /* multipath.h */
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 92e94f8..061b6b0 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -23,6 +23,7 @@
> #include "classifier.h"
> #include "dynamic-string.h"
> #include "meta-flow.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> @@ -789,180 +790,185 @@ nx_match_from_string(const char *s, struct ofpbuf *b)
> }
>
> void
> -nxm_parse_reg_move(struct nx_action_reg_move *move, const char *s)
> +nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s)
> {
> const char *full_s = s;
> - struct mf_subfield src, dst;
>
> - s = mf_parse_subfield(&src, s);
> + s = mf_parse_subfield(&move->src, s);
> if (strncmp(s, "->", 2)) {
> ovs_fatal(0, "%s: missing `->' following source", full_s);
> }
> s += 2;
> - s = mf_parse_subfield(&dst, s);
> + s = mf_parse_subfield(&move->dst, s);
> if (*s != '\0') {
> ovs_fatal(0, "%s: trailing garbage following destination", full_s);
> }
>
> - if (src.n_bits != dst.n_bits) {
> + if (move->src.n_bits != move->dst.n_bits) {
> ovs_fatal(0, "%s: source field is %d bits wide but destination is "
> - "%d bits wide", full_s, src.n_bits, dst.n_bits);
> + "%d bits wide", full_s,
> + move->src.n_bits, move->dst.n_bits);
> }
> -
> - ofputil_init_NXAST_REG_MOVE(move);
> - move->n_bits = htons(src.n_bits);
> - move->src_ofs = htons(src.ofs);
> - move->dst_ofs = htons(dst.ofs);
> - move->src = htonl(src.field->nxm_header);
> - move->dst = htonl(dst.field->nxm_header);
> }
>
> void
> -nxm_parse_reg_load(struct nx_action_reg_load *load, const char *s)
> +nxm_parse_reg_load(struct ofpact_reg_load *load, const char *s)
> {
> const char *full_s = s;
> - struct mf_subfield dst;
> - uint64_t value;
>
> - value = strtoull(s, (char **) &s, 0);
> + load->value = strtoull(s, (char **) &s, 0);
> if (strncmp(s, "->", 2)) {
> ovs_fatal(0, "%s: missing `->' following value", full_s);
> }
> s += 2;
> - s = mf_parse_subfield(&dst, s);
> + s = mf_parse_subfield(&load->dst, s);
> if (*s != '\0') {
> ovs_fatal(0, "%s: trailing garbage following destination", full_s);
> }
>
> - if (dst.n_bits < 64 && (value >> dst.n_bits) != 0) {
> - ovs_fatal(0, "%s: value %"PRIu64" does not fit into %u bits",
> - full_s, value, dst.n_bits);
> + if (load->dst.n_bits < 64 && (load->value >> load->dst.n_bits) != 0) {
> + ovs_fatal(0, "%s: value %"PRIu64" does not fit into %d bits",
> + full_s, load->value, load->dst.n_bits);
> }
> -
> - ofputil_init_NXAST_REG_LOAD(load);
> - load->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
> - load->dst = htonl(dst.field->nxm_header);
> - load->value = htonll(value);
> }
>
> /* nxm_format_reg_move(), nxm_format_reg_load(). */
>
> void
> -nxm_format_reg_move(const struct nx_action_reg_move *move, struct ds *s)
> +nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s)
> {
> - struct mf_subfield src, dst;
> -
> - nxm_decode_discrete(&src, move->src, move->src_ofs, move->n_bits);
> - nxm_decode_discrete(&dst, move->dst, move->dst_ofs, move->n_bits);
> -
> ds_put_format(s, "move:");
> - mf_format_subfield(&src, s);
> + mf_format_subfield(&move->src, s);
> ds_put_cstr(s, "->");
> - mf_format_subfield(&dst, s);
> + mf_format_subfield(&move->dst, s);
> }
>
> void
> -nxm_format_reg_load(const struct nx_action_reg_load *load, struct ds *s)
> +nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s)
> +{
> + ds_put_format(s, "load:%#"PRIx64"->", load->value);
> + mf_format_subfield(&load->dst, s);
> +}
> +
> +enum ofperr
> +nxm_reg_move_from_openflow(const struct nx_action_reg_move *narm,
> + struct ofpbuf *ofpacts)
> {
> - struct mf_subfield dst;
> + struct ofpact_reg_move *move;
>
> - ds_put_format(s, "load:%#"PRIx64"->", ntohll(load->value));
> + move = ofpact_put_REG_MOVE(ofpacts);
> + move->src.field = mf_from_nxm_header(ntohl(narm->src));
> + move->src.ofs = ntohs(narm->src_ofs);
> + move->src.n_bits = ntohs(narm->n_bits);
> + move->dst.field = mf_from_nxm_header(ntohl(narm->dst));
> + move->dst.ofs = ntohs(narm->dst_ofs);
> + move->dst.n_bits = ntohs(narm->n_bits);
>
> - nxm_decode(&dst, load->dst, load->ofs_nbits);
> - mf_format_subfield(&dst, s);
> + return nxm_reg_move_check(move, NULL);
> }
> -
> -/* nxm_check_reg_move(), nxm_check_reg_load(). */
>
> enum ofperr
> -nxm_check_reg_move(const struct nx_action_reg_move *action,
> - const struct flow *flow)
> +nxm_reg_load_from_openflow(const struct nx_action_reg_load *narl,
> + struct ofpbuf *ofpacts)
> {
> - struct mf_subfield src;
> - struct mf_subfield dst;
> - int error;
> + struct ofpact_reg_load *load;
>
> - nxm_decode_discrete(&src, action->src, action->src_ofs, action->n_bits);
> - error = mf_check_src(&src, flow);
> - if (error) {
> - return error;
> + load = ofpact_put_REG_LOAD(ofpacts);
> + load->dst.field = mf_from_nxm_header(ntohl(narl->dst));
> + load->dst.ofs = nxm_decode_ofs(narl->ofs_nbits);
> + load->dst.n_bits = nxm_decode_n_bits(narl->ofs_nbits);
> + load->value = ntohll(narl->value);
> +
> + /* Reject 'narl' if a bit numbered 'n_bits' or higher is set to 1 in
> + * narl->value. */
> + if (load->dst.n_bits < 64 && load->value >> load->dst.n_bits) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> }
>
> - nxm_decode_discrete(&dst, action->dst, action->dst_ofs, action->n_bits);
> - return mf_check_dst(&dst, flow);
> + return nxm_reg_load_check(load, NULL);
> }
> -
> +
> enum ofperr
> -nxm_check_reg_load(const struct nx_action_reg_load *action,
> - const struct flow *flow)
> +nxm_reg_move_check(const struct ofpact_reg_move *move, const struct flow *flow)
> {
> - struct mf_subfield dst;
> enum ofperr error;
>
> - nxm_decode(&dst, action->dst, action->ofs_nbits);
> - error = mf_check_dst(&dst, flow);
> + error = mf_check_src(&move->src, flow);
> if (error) {
> return error;
> }
>
> - /* Reject 'action' if a bit numbered 'n_bits' or higher is set to 1 in
> - * action->value. */
> - if (dst.n_bits < 64 && ntohll(action->value) >> dst.n_bits) {
> - return OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> + return mf_check_dst(&move->dst, NULL);
> +}
>
> - return 0;
> +enum ofperr
> +nxm_reg_load_check(const struct ofpact_reg_load *load, const struct flow *flow)
> +{
> + return mf_check_dst(&load->dst, flow);
> +}
> +
> +void
> +nxm_reg_move_to_openflow(const struct ofpact_reg_move *move,
> + struct ofpbuf *openflow)
> +{
> + struct nx_action_reg_move *narm;
> +
> + narm = ofputil_put_NXAST_REG_MOVE(openflow);
> + narm->n_bits = htons(move->dst.n_bits);
> + narm->src_ofs = htons(move->src.ofs);
> + narm->dst_ofs = htons(move->dst.ofs);
> + narm->src = htonl(move->src.field->nxm_header);
> + narm->dst = htonl(move->dst.field->nxm_header);
> +}
> +
> +void
> +nxm_reg_load_to_openflow(const struct ofpact_reg_load *load,
> + struct ofpbuf *openflow)
> +{
> + struct nx_action_reg_load *narl;
> +
> + narl = ofputil_put_NXAST_REG_LOAD(openflow);
> + narl->ofs_nbits = nxm_encode_ofs_nbits(load->dst.ofs, load->dst.n_bits);
> + narl->dst = htonl(load->dst.field->nxm_header);
> + narl->value = htonll(load->value);
> }
>
> /* nxm_execute_reg_move(), nxm_execute_reg_load(). */
>
> void
> -nxm_execute_reg_move(const struct nx_action_reg_move *action,
> +nxm_execute_reg_move(const struct ofpact_reg_move *move,
> struct flow *flow)
> {
> - struct mf_subfield src, dst;
> union mf_value src_value;
> union mf_value dst_value;
>
> - nxm_decode_discrete(&src, action->src, action->src_ofs, action->n_bits);
> - nxm_decode_discrete(&dst, action->dst, action->dst_ofs, action->n_bits);
> -
> - mf_get_value(dst.field, flow, &dst_value);
> - mf_get_value(src.field, flow, &src_value);
> - bitwise_copy(&src_value, src.field->n_bytes, src.ofs,
> - &dst_value, dst.field->n_bytes, dst.ofs,
> - src.n_bits);
> - mf_set_flow_value(dst.field, &dst_value, flow);
> + mf_get_value(move->dst.field, flow, &dst_value);
> + mf_get_value(move->src.field, flow, &src_value);
> + bitwise_copy(&src_value, move->src.field->n_bytes, move->src.ofs,
> + &dst_value, move->dst.field->n_bytes, move->dst.ofs,
> + move->src.n_bits);
> + mf_set_flow_value(move->dst.field, &dst_value, flow);
> }
>
> void
> -nxm_execute_reg_load(const struct nx_action_reg_load *action,
> - struct flow *flow)
> +nxm_execute_reg_load(const struct ofpact_reg_load *load, struct flow *flow)
> {
> - struct mf_subfield dst;
> -
> - nxm_decode(&dst, action->dst, action->ofs_nbits);
> - mf_set_subfield_value(&dst, ntohll(action->value), flow);
> + nxm_reg_load(&load->dst, load->value, flow);
> }
>
> -/* Initializes 'sf->field' with the field corresponding to the given NXM
> - * 'header' and 'sf->ofs' and 'sf->n_bits' decoded from 'ofs_nbits' with
> - * nxm_decode_ofs() and nxm_decode_n_bits(), respectively.
> - *
> - * Afterward, 'sf' might be invalid in a few different ways:
> - *
> - * - 'sf->field' will be NULL if 'header' is unknown.
> - *
> - * - 'sf->ofs' and 'sf->n_bits' might exceed the width of sf->field.
> - *
> - * The caller should call mf_check_src() or mf_check_dst() to check for these
> - * problems. */
> void
> -nxm_decode(struct mf_subfield *sf, ovs_be32 header, ovs_be16 ofs_nbits)
> +nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data,
> + struct flow *flow)
> {
> - sf->field = mf_from_nxm_header(ntohl(header));
> - sf->ofs = nxm_decode_ofs(ofs_nbits);
> - sf->n_bits = nxm_decode_n_bits(ofs_nbits);
> + union mf_value dst_value;
> + union mf_value src_value;
> +
> + mf_get_value(dst->field, flow, &dst_value);
> + src_value.be64 = htonll(src_data);
> + bitwise_copy(&src_value, sizeof src_value.be64, 0,
> + &dst_value, dst->field->n_bytes, dst->ofs,
> + dst->n_bits);
> + mf_set_flow_value(dst->field, &dst_value, flow);
> }
>
> /* Initializes 'sf->field' with the field corresponding to the given NXM
> diff --git a/lib/nx-match.h b/lib/nx-match.h
> index c814275..c57e240 100644
> --- a/lib/nx-match.h
> +++ b/lib/nx-match.h
> @@ -21,6 +21,7 @@
> #include <sys/types.h>
> #include <netinet/in.h>
> #include "flow.h"
> +#include "ofp-errors.h"
> #include "openvswitch/types.h"
> #include "ofp-errors.h"
>
> @@ -28,6 +29,8 @@ struct cls_rule;
> struct ds;
> struct flow;
> struct mf_subfield;
> +struct ofpact_reg_move;
> +struct ofpact_reg_load;
> struct ofpbuf;
> struct nx_action_reg_load;
> struct nx_action_reg_move;
> @@ -49,19 +52,31 @@ int nx_put_match(struct ofpbuf *, bool oxm, const struct cls_rule *,
> char *nx_match_to_string(const uint8_t *, unsigned int match_len);
> int nx_match_from_string(const char *, struct ofpbuf *);
>
> -void nxm_parse_reg_move(struct nx_action_reg_move *, const char *);
> -void nxm_parse_reg_load(struct nx_action_reg_load *, const char *);
> +void nxm_parse_reg_move(struct ofpact_reg_move *, const char *);
> +void nxm_parse_reg_load(struct ofpact_reg_load *, const char *);
> +
> +void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *);
> +void nxm_format_reg_load(const struct ofpact_reg_load *, struct ds *);
>
> -void nxm_format_reg_move(const struct nx_action_reg_move *, struct ds *);
> -void nxm_format_reg_load(const struct nx_action_reg_load *, struct ds *);
> +enum ofperr nxm_reg_move_from_openflow(const struct nx_action_reg_move *,
> + struct ofpbuf *ofpacts);
> +enum ofperr nxm_reg_load_from_openflow(const struct nx_action_reg_load *,
> + struct ofpbuf *ofpacts);
>
> -enum ofperr nxm_check_reg_move(const struct nx_action_reg_move *,
> +enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *,
> const struct flow *);
> -enum ofperr nxm_check_reg_load(const struct nx_action_reg_load *,
> +enum ofperr nxm_reg_load_check(const struct ofpact_reg_load *,
> const struct flow *);
>
> -void nxm_execute_reg_move(const struct nx_action_reg_move *, struct flow *);
> -void nxm_execute_reg_load(const struct nx_action_reg_load *, struct flow *);
> +void nxm_reg_move_to_openflow(const struct ofpact_reg_move *,
> + struct ofpbuf *openflow);
> +void nxm_reg_load_to_openflow(const struct ofpact_reg_load *,
> + struct ofpbuf *openflow);
> +
> +void nxm_execute_reg_move(const struct ofpact_reg_move *, struct flow *);
> +void nxm_execute_reg_load(const struct ofpact_reg_load *, struct flow *);
> +void nxm_reg_load(const struct mf_subfield *, uint64_t src_data,
> + struct flow *);
>
> int nxm_field_bytes(uint32_t header);
> int nxm_field_bits(uint32_t header);
> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
> new file mode 100644
> index 0000000..cf8ea95
> --- /dev/null
> +++ b/lib/ofp-actions.c
> @@ -0,0 +1,1213 @@
> +/*
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +#include "ofp-actions.h"
> +#include "autopath.h"
> +#include "bundle.h"
> +#include "byte-order.h"
> +#include "compiler.h"
> +#include "dynamic-string.h"
> +#include "learn.h"
> +#include "meta-flow.h"
> +#include "multipath.h"
> +#include "nx-match.h"
> +#include "ofp-util.h"
> +#include "ofpbuf.h"
> +#include "vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(ofp_actions);
> +
> +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> +
> +/* Converting OpenFlow 1.0 to ofpacts. */
> +
> +static enum ofperr
> +output_from_openflow10(const struct ofp_action_output *oao,
> + struct ofpbuf *out)
> +{
> + struct ofpact_output *output;
> +
> + output = ofpact_put_OUTPUT(out);
> + output->port = ntohs(oao->port);
> + output->max_len = ntohs(oao->max_len);
> +
> + return ofputil_check_output_port(output->port, OFPP_MAX);
> +}
> +
> +static enum ofperr
> +enqueue_from_openflow10(const struct ofp_action_enqueue *oae,
> + struct ofpbuf *out)
> +{
> + struct ofpact_enqueue *enqueue;
> +
> + enqueue = ofpact_put_ENQUEUE(out);
> + enqueue->port = ntohs(oae->port);
> + enqueue->queue = ntohl(oae->queue_id);
> + if (enqueue->port >= OFPP_MAX && enqueue->port != OFPP_IN_PORT
> + && enqueue->port != OFPP_LOCAL) {
> + return OFPERR_OFPBAC_BAD_OUT_PORT;
> + }
> + return 0;
> +}
> +
> +static void
> +resubmit_from_openflow(const struct nx_action_resubmit *nar,
> + struct ofpbuf *out)
> +{
> + struct ofpact_resubmit *resubmit;
> +
> + resubmit = ofpact_put_RESUBMIT(out);
> + resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT;
> + resubmit->in_port = ntohs(nar->in_port);
> + resubmit->table_id = 0xff;
> +}
> +
> +static enum ofperr
> +resubmit_table_from_openflow(const struct nx_action_resubmit *nar,
> + struct ofpbuf *out)
> +{
> + struct ofpact_resubmit *resubmit;
> +
> + if (nar->pad[0] || nar->pad[1] || nar->pad[2]) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + }
> +
> + resubmit = ofpact_put_RESUBMIT(out);
> + resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT_TABLE;
> + resubmit->in_port = ntohs(nar->in_port);
> + resubmit->table_id = nar->table;
> + return 0;
> +}
> +
> +static enum ofperr
> +output_reg_from_openflow(const struct nx_action_output_reg *naor,
> + struct ofpbuf *out)
> +{
> + struct ofpact_output_reg *output_reg;
> +
> + if (!is_all_zeros(naor->zero, sizeof naor->zero)) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + }
> +
> + output_reg = ofpact_put_OUTPUT_REG(out);
> + output_reg->src.field = mf_from_nxm_header(ntohl(naor->src));
> + output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits);
> + output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits);
> + output_reg->max_len = ntohs(naor->max_len);
> +
> + return mf_check_src(&output_reg->src, NULL);
> +}
> +
> +static void
> +fin_timeout_from_openflow(const struct nx_action_fin_timeout *naft,
> + struct ofpbuf *out)
> +{
> + struct ofpact_fin_timeout *oft;
> +
> + oft = ofpact_put_FIN_TIMEOUT(out);
> + oft->fin_idle_timeout = ntohs(naft->fin_idle_timeout);
> + oft->fin_hard_timeout = ntohs(naft->fin_hard_timeout);
> +}
> +
> +static void
> +controller_from_openflow(const struct nx_action_controller *nac,
> + struct ofpbuf *out)
> +{
> + struct ofpact_controller *oc;
> +
> + oc = ofpact_put_CONTROLLER(out);
> + oc->max_len = ntohs(nac->max_len);
> + oc->controller_id = ntohs(nac->controller_id);
> + oc->reason = nac->reason;
> +}
> +
> +static void
> +note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
> +{
> + struct ofpact_note *note;
> + unsigned int length;
> +
> + length = ntohs(nan->len) - offsetof(struct nx_action_note, note);
> + note = ofpact_put(out, OFPACT_NOTE,
> + offsetof(struct ofpact_note, data) + length);
> + note->length = length;
> + memcpy(note->data, nan->note, length);
> +}
> +
> +static enum ofperr
> +decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
> +{
> + const struct nx_action_header *nah = (const struct nx_action_header *) a;
> + uint16_t len = ntohs(a->header.len);
> +
> + if (len < sizeof(struct nx_action_header)) {
> + return OFPERR_OFPBAC_BAD_LEN;
> + } else if (a->vendor.vendor != CONSTANT_HTONL(NX_VENDOR_ID)) {
> + return OFPERR_OFPBAC_BAD_VENDOR;
> + }
> +
> + switch (nah->subtype) {
> +#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
> + case CONSTANT_HTONS(ENUM): \
> + if (EXTENSIBLE \
> + ? len >= sizeof(struct STRUCT) \
> + : len == sizeof(struct STRUCT)) { \
> + *code = OFPUTIL_##ENUM; \
> + return 0; \
> + } else { \
> + return OFPERR_OFPBAC_BAD_LEN; \
> + } \
> + NOT_REACHED();
> +#include "ofp-util.def"
> +
> + case CONSTANT_HTONS(NXAST_SNAT__OBSOLETE):
> + case CONSTANT_HTONS(NXAST_DROP_SPOOFED_ARP__OBSOLETE):
> + default:
> + return OFPERR_OFPBAC_BAD_TYPE;
> + }
> +}
> +
> +/* Parses 'a' to determine its type. On success stores the correct type into
> + * '*code' and returns 0. On failure returns an OFPERR_* error code and
> + * '*code' is indeterminate.
> + *
> + * The caller must have already verified that 'a''s length is potentially
> + * correct (that is, a->header.len is nonzero and a multiple of sizeof(union
> + * ofp_action) and no longer than the amount of space allocated to 'a').
> + *
> + * This function verifies that 'a''s length is correct for the type of action
> + * that it represents. */
> +static enum ofperr
> +decode_openflow10_action(const union ofp_action *a,
> + enum ofputil_action_code *code)
> +{
> + switch (a->type) {
> + case CONSTANT_HTONS(OFPAT10_VENDOR):
> + return decode_nxast_action(a, code);
> +
> +#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
> + case CONSTANT_HTONS(ENUM): \
> + if (a->header.len == htons(sizeof(struct STRUCT))) { \
> + *code = OFPUTIL_##ENUM; \
> + return 0; \
> + } else { \
> + return OFPERR_OFPBAC_BAD_LEN; \
> + } \
> + break;
> +#include "ofp-util.def"
> +
> + default:
> + return OFPERR_OFPBAC_BAD_TYPE;
> + }
> +}
> +
> +static enum ofperr
> +ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
> +{
> + const struct nx_action_resubmit *nar;
> + const struct nx_action_set_tunnel *nast;
> + const struct nx_action_set_queue *nasq;
> + const struct nx_action_note *nan;
> + const struct nx_action_set_tunnel64 *nast64;
> + struct ofpact_tunnel *tunnel;
> + enum ofputil_action_code code;
> + enum ofperr error;
> +
> + error = decode_openflow10_action(a, &code);
> + if (error) {
> + return error;
> + }
> +
> + switch (code) {
> + case OFPUTIL_ACTION_INVALID:
> + NOT_REACHED();
> +
> + case OFPUTIL_OFPAT10_OUTPUT:
> + return output_from_openflow10((const struct ofp_action_output *) a,
> + out);
> +
> + case OFPUTIL_OFPAT10_SET_VLAN_VID:
> + if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + }
> + ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_VLAN_PCP:
> + if (a->vlan_pcp.vlan_pcp & ~7) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + }
> + ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
> + break;
> +
> + case OFPUTIL_OFPAT10_STRIP_VLAN:
> + ofpact_put_STRIP_VLAN(out);
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_DL_SRC:
> + memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
> + ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_DL_DST:
> + memcpy(ofpact_put_SET_ETH_DST(out)->mac,
> + ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_NW_SRC:
> + ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_NW_DST:
> + ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_NW_TOS:
> + if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
> + return OFPERR_OFPBAC_BAD_ARGUMENT;
> + }
> + ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_TP_SRC:
> + ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
> + break;
> +
> + case OFPUTIL_OFPAT10_SET_TP_DST:
> + ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
> +
> + break;
> +
> + case OFPUTIL_OFPAT10_ENQUEUE:
> + error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
> + out);
> + break;
> +
> + case OFPUTIL_NXAST_RESUBMIT:
> + resubmit_from_openflow((const struct nx_action_resubmit *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_SET_TUNNEL:
> + nast = (const struct nx_action_set_tunnel *) a;
> + tunnel = ofpact_put_SET_TUNNEL(out);
> + tunnel->ofpact.compat = code;
> + tunnel->tun_id = ntohl(nast->tun_id);
> + break;
> +
> + case OFPUTIL_NXAST_SET_QUEUE:
> + nasq = (const struct nx_action_set_queue *) a;
> + ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id);
> + break;
> +
> + case OFPUTIL_NXAST_POP_QUEUE:
> + ofpact_put_POP_QUEUE(out);
> + break;
> +
> + case OFPUTIL_NXAST_REG_MOVE:
> + error = nxm_reg_move_from_openflow(
> + (const struct nx_action_reg_move *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_REG_LOAD:
> + error = nxm_reg_load_from_openflow(
> + (const struct nx_action_reg_load *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_NOTE:
> + nan = (const struct nx_action_note *) a;
> + note_from_openflow(nan, out);
> + break;
> +
> + case OFPUTIL_NXAST_SET_TUNNEL64:
> + nast64 = (const struct nx_action_set_tunnel64 *) a;
> + tunnel = ofpact_put_SET_TUNNEL(out);
> + tunnel->ofpact.compat = code;
> + tunnel->tun_id = ntohll(nast64->tun_id);
> + break;
> +
> + case OFPUTIL_NXAST_MULTIPATH:
> + error = multipath_from_openflow((const struct nx_action_multipath *) a,
> + ofpact_put_MULTIPATH(out));
> + break;
> +
> + case OFPUTIL_NXAST_AUTOPATH:
> + error = autopath_from_openflow((const struct nx_action_autopath *) a,
> + ofpact_put_AUTOPATH(out));
> + break;
> +
> + case OFPUTIL_NXAST_BUNDLE:
> + case OFPUTIL_NXAST_BUNDLE_LOAD:
> + error = bundle_from_openflow((const struct nx_action_bundle *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_OUTPUT_REG:
> + error = output_reg_from_openflow(
> + (const struct nx_action_output_reg *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_RESUBMIT_TABLE:
> + nar = (const struct nx_action_resubmit *) a;
> + error = resubmit_table_from_openflow(nar, out);
> + break;
> +
> + case OFPUTIL_NXAST_LEARN:
> + error = learn_from_openflow((const struct nx_action_learn *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_EXIT:
> + ofpact_put_EXIT(out);
> + break;
> +
> + case OFPUTIL_NXAST_DEC_TTL:
> + ofpact_put_DEC_TTL(out);
> + break;
> +
> + case OFPUTIL_NXAST_FIN_TIMEOUT:
> + fin_timeout_from_openflow(
> + (const struct nx_action_fin_timeout *) a, out);
> + break;
> +
> + case OFPUTIL_NXAST_CONTROLLER:
> + controller_from_openflow((const struct nx_action_controller *) a, out);
> + break;
> + }
> +
> + return error;
> +}
> +
> +static inline union ofp_action *
> +action_next(const union ofp_action *a)
> +{
> + return ((union ofp_action *) (void *)
> + ((uint8_t *) a + ntohs(a->header.len)));
> +}
> +
> +static inline bool
> +action_is_valid(const union ofp_action *a, size_t n_actions)
> +{
> + uint16_t len = ntohs(a->header.len);
> + return (!(len % OFP_ACTION_ALIGN)
> + && len >= sizeof *a
> + && len / sizeof *a <= n_actions);
> +}
> +
> +/* This macro is careful to check for actions with bad lengths. */
> +#define ACTION_FOR_EACH(ITER, LEFT, ACTIONS, N_ACTIONS) \
> + for ((ITER) = (ACTIONS), (LEFT) = (N_ACTIONS); \
> + (LEFT) > 0 && action_is_valid(ITER, LEFT); \
> + ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
> + (ITER) = action_next(ITER)))
> +
> +static enum ofperr
> +ofpact_from_openflow10(const union ofp_action *in, size_t n_in,
> + struct ofpbuf *out)
> +{
> + const union ofp_action *a;
> + size_t left;
> +
> + ACTION_FOR_EACH (a, left, in, n_in) {
> + enum ofperr error = ofpact_from_openflow10__(a, out);
> + if (error) {
> + VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
> + (a - in) * sizeof *a, ofperr_get_name(error));
> + return error;
> + }
> + }
> + if (left) {
> + VLOG_WARN_RL(&rl, "bad action format at offset %zu",
> + (n_in - left) * sizeof *a);
> + return OFPERR_OFPBAC_BAD_LEN;
> + }
> +
> + ofpact_put_END(out);
> +
> + return 0;
> +}
> +
> +/* Attempts to convert 'actions_len' bytes of OpenFlow actions from the front
> + * of 'openflow' into ofpacts. On success, replaces any existing content in
> + * 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'. Returns 0
> + * if successful, otherwise an OpenFlow error.
> + *
> + * This function does not check that the actions are valid in a given context.
> + * The caller should do so, with ofpacts_check(). */
> +enum ofperr
> +ofpacts_pull_openflow(struct ofpbuf *openflow, unsigned int actions_len,
> + struct ofpbuf *ofpacts)
> +{
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> + const union ofp_action *actions;
> + enum ofperr error;
> +
> + ofpbuf_clear(ofpacts);
> +
> + if (actions_len % OFP_ACTION_ALIGN != 0) {
> + VLOG_WARN_RL(&rl, "OpenFlow message actions length %u is not a "
> + "multiple of %d", actions_len, OFP_ACTION_ALIGN);
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> +
> + actions = ofpbuf_try_pull(openflow, actions_len);
> + if (actions == NULL) {
> + VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds "
> + "remaining message length (%zu)",
> + actions_len, openflow->size);
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> +
> + error = ofpact_from_openflow10(actions, actions_len / OFP_ACTION_ALIGN,
> + ofpacts);
> + if (error) {
> + ofpbuf_clear(ofpacts);
> + }
> + return 0;
> +}
> +
> +static enum ofperr
> +ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
> +{
> + const struct ofpact_enqueue *enqueue;
> +
> + switch (a->type) {
> + case OFPACT_END:
> + return 0;
> +
> + case OFPACT_OUTPUT:
> + return ofputil_check_output_port(ofpact_get_OUTPUT(a)->port,
> + max_ports);
> +
> + case OFPACT_CONTROLLER:
> + return 0;
> +
> + case OFPACT_ENQUEUE:
> + enqueue = ofpact_get_ENQUEUE(a);
> + if (enqueue->port >= max_ports && enqueue->port != OFPP_IN_PORT
> + && enqueue->port != OFPP_LOCAL) {
> + return OFPERR_OFPBAC_BAD_OUT_PORT;
> + }
> + return 0;
> +
> + case OFPACT_OUTPUT_REG:
> + return mf_check_src(&ofpact_get_OUTPUT_REG(a)->src, flow);
> +
> + case OFPACT_BUNDLE:
> + return bundle_check(ofpact_get_BUNDLE(a), max_ports, flow);
> +
> + case OFPACT_SET_VLAN_VID:
> + case OFPACT_SET_VLAN_PCP:
> + case OFPACT_STRIP_VLAN:
> + case OFPACT_SET_ETH_SRC:
> + case OFPACT_SET_ETH_DST:
> + case OFPACT_SET_IPV4_SRC:
> + case OFPACT_SET_IPV4_DST:
> + case OFPACT_SET_IPV4_DSCP:
> + case OFPACT_SET_L4_SRC_PORT:
> + case OFPACT_SET_L4_DST_PORT:
> + return 0;
> +
> + case OFPACT_REG_MOVE:
> + return nxm_reg_move_check(ofpact_get_REG_MOVE(a), flow);
> +
> + case OFPACT_REG_LOAD:
> + return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
> +
> + case OFPACT_DEC_TTL:
> + case OFPACT_SET_TUNNEL:
> + case OFPACT_SET_QUEUE:
> + case OFPACT_POP_QUEUE:
> + case OFPACT_FIN_TIMEOUT:
> + case OFPACT_RESUBMIT:
> + return 0;
> +
> + case OFPACT_LEARN:
> + return learn_check(ofpact_get_LEARN(a), flow);
> +
> + case OFPACT_MULTIPATH:
> + return multipath_check(ofpact_get_MULTIPATH(a), flow);
> +
> + case OFPACT_AUTOPATH:
> + return autopath_check(ofpact_get_AUTOPATH(a), flow);
> +
> + case OFPACT_NOTE:
> + case OFPACT_EXIT:
> + return 0;
> +
> + default:
> + NOT_REACHED();
> + }
> +}
> +
> +/* Checks that the actions in 'ofpacts' (terminated by OFPACT_END) are
> + * appropriate for a packet with the prerequisites satisfied by 'flow' in a
> + * switch with no more than 'max_ports' ports. */
> +enum ofperr
> +ofpacts_check(const struct ofpact ofpacts[],
> + const struct flow *flow, int max_ports)
> +{
> + const struct ofpact *a;
> +
> + OFPACT_FOR_EACH (a, ofpacts) {
> + enum ofperr error = ofpact_check__(a, flow, max_ports);
> + if (error) {
> + return error;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Converting ofpacts to Nicira OpenFlow extensions. */
> +
> +static void
> +ofpact_output_reg_to_nxast(const struct ofpact_output_reg *output_reg,
> + struct ofpbuf *out)
> +{
> + struct nx_action_output_reg *naor = ofputil_put_NXAST_OUTPUT_REG(out);
> +
> + naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
> + output_reg->src.n_bits);
> + naor->src = htonl(output_reg->src.field->nxm_header);
> + naor->max_len = htons(output_reg->max_len);
> +}
> +
> +static void
> +ofpact_resubmit_to_nxast(const struct ofpact_resubmit *resubmit,
> + struct ofpbuf *out)
> +{
> + struct nx_action_resubmit *nar;
> +
> + if (resubmit->table_id == 0xff
> + && resubmit->ofpact.compat != OFPUTIL_NXAST_RESUBMIT_TABLE) {
> + nar = ofputil_put_NXAST_RESUBMIT(out);
> + } else {
> + nar = ofputil_put_NXAST_RESUBMIT_TABLE(out);
> + nar->table = resubmit->table_id;
> + }
> + nar->in_port = htons(resubmit->in_port);
> +}
> +
> +static void
> +ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel *tunnel,
> + struct ofpbuf *out)
> +{
> + uint64_t tun_id = tunnel->tun_id;
> +
> + if (tun_id <= UINT32_MAX
> + && tunnel->ofpact.compat != OFPUTIL_NXAST_SET_TUNNEL64) {
> + ofputil_put_NXAST_SET_TUNNEL(out)->tun_id = htonl(tun_id);
> + } else {
> + ofputil_put_NXAST_SET_TUNNEL64(out)->tun_id = htonll(tun_id);
> + }
> +}
> +
> +static void
> +ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
> +{
> + size_t start_ofs = out->size;
> + struct nx_action_note *nan;
> + unsigned int remainder;
> + unsigned int len;
> +
> + nan = ofputil_put_NXAST_NOTE(out);
> + out->size -= sizeof nan->note;
> +
> + ofpbuf_put(out, note->data, note->length);
> +
> + len = out->size - start_ofs;
> + remainder = len % OFP_ACTION_ALIGN;
> + if (remainder) {
> + ofpbuf_put_zeros(out, OFP_ACTION_ALIGN - remainder);
> + }
> + nan = (struct nx_action_note *)((char *)out->data + start_ofs);
> + nan->len = htons(out->size - start_ofs);
> +}
> +
> +static void
> +ofpact_controller_to_nxast(const struct ofpact_controller *oc,
> + struct ofpbuf *out)
> +{
> + struct nx_action_controller *nac;
> +
> + nac = ofputil_put_NXAST_CONTROLLER(out);
> + nac->max_len = htons(oc->max_len);
> + nac->controller_id = htons(oc->controller_id);
> + nac->reason = oc->reason;
> +}
> +
> +static void
> +ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
> + struct ofpbuf *out)
> +{
> + struct nx_action_fin_timeout *naft = ofputil_put_NXAST_FIN_TIMEOUT(out);
> + naft->fin_idle_timeout = htons(fin_timeout->fin_idle_timeout);
> + naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout);
> +}
> +
> +static void
> +ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
> +{
> + switch (a->type) {
> + case OFPACT_CONTROLLER:
> + ofpact_controller_to_nxast(ofpact_get_CONTROLLER(a), out);
> + break;
> +
> + case OFPACT_OUTPUT_REG:
> + ofpact_output_reg_to_nxast(ofpact_get_OUTPUT_REG(a), out);
> + break;
> +
> + case OFPACT_BUNDLE:
> + bundle_to_openflow(ofpact_get_BUNDLE(a), out);
> + break;
> +
> + case OFPACT_REG_MOVE:
> + nxm_reg_move_to_openflow(ofpact_get_REG_MOVE(a), out);
> + break;
> +
> + case OFPACT_REG_LOAD:
> + nxm_reg_load_to_openflow(ofpact_get_REG_LOAD(a), out);
> + break;
> +
> + case OFPACT_DEC_TTL:
> + ofputil_put_NXAST_DEC_TTL(out);
> + break;
> +
> + case OFPACT_SET_TUNNEL:
> + ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
> + break;
> +
> + case OFPACT_SET_QUEUE:
> + ofputil_put_NXAST_SET_QUEUE(out)->queue_id
> + = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
> + break;
> +
> + case OFPACT_POP_QUEUE:
> + ofputil_put_NXAST_POP_QUEUE(out);
> + break;
> +
> + case OFPACT_FIN_TIMEOUT:
> + ofpact_fin_timeout_to_nxast(ofpact_get_FIN_TIMEOUT(a), out);
> + break;
> +
> + case OFPACT_RESUBMIT:
> + ofpact_resubmit_to_nxast(ofpact_get_RESUBMIT(a), out);
> + break;
> +
> + case OFPACT_LEARN:
> + learn_to_openflow(ofpact_get_LEARN(a), out);
> + break;
> +
> + case OFPACT_MULTIPATH:
> + multipath_to_openflow(ofpact_get_MULTIPATH(a), out);
> + break;
> +
> + case OFPACT_AUTOPATH:
> + autopath_to_openflow(ofpact_get_AUTOPATH(a), out);
> + break;
> +
> + case OFPACT_NOTE:
> + ofpact_note_to_nxast(ofpact_get_NOTE(a), out);
> + break;
> +
> + case OFPACT_EXIT:
> + ofputil_put_NXAST_EXIT(out);
> + break;
> +
> + case OFPACT_END:
> + case OFPACT_OUTPUT:
> + case OFPACT_ENQUEUE:
> + case OFPACT_SET_VLAN_VID:
> + case OFPACT_SET_VLAN_PCP:
> + case OFPACT_STRIP_VLAN:
> + case OFPACT_SET_ETH_SRC:
> + case OFPACT_SET_ETH_DST:
> + case OFPACT_SET_IPV4_SRC:
> + case OFPACT_SET_IPV4_DST:
> + case OFPACT_SET_IPV4_DSCP:
> + case OFPACT_SET_L4_SRC_PORT:
> + case OFPACT_SET_L4_DST_PORT:
> + NOT_REACHED();
> + }
> +}
> +
> +/* Converting ofpacts to OpenFlow 1.0. */
> +
> +static void
> +ofpact_output_to_openflow10(const struct ofpact_output *output,
> + struct ofpbuf *out)
> +{
> + struct ofp_action_output *oao;
> +
> + oao = ofputil_put_OFPAT10_OUTPUT(out);
> + oao->port = htons(output->port);
> + oao->max_len = htons(output->max_len);
> +}
> +
> +static void
> +ofpact_enqueue_to_openflow10(const struct ofpact_enqueue *enqueue,
> + struct ofpbuf *out)
> +{
> + struct ofp_action_enqueue *oae;
> +
> + oae = ofputil_put_OFPAT10_ENQUEUE(out);
> + oae->port = htons(enqueue->port);
> + oae->queue_id = htonl(enqueue->queue);
> +}
> +
> +static void
> +ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
> +{
> + switch (a->type) {
> + case OFPACT_END:
> + NOT_REACHED();
> +
> + case OFPACT_OUTPUT:
> + ofpact_output_to_openflow10(ofpact_get_OUTPUT(a), out);
> + break;
> +
> + case OFPACT_ENQUEUE:
> + ofpact_enqueue_to_openflow10(ofpact_get_ENQUEUE(a), out);
> + break;
> +
> + case OFPACT_SET_VLAN_VID:
> + ofputil_put_OFPAT10_SET_VLAN_VID(out)->vlan_vid
> + = htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid);
> + break;
> +
> + case OFPACT_SET_VLAN_PCP:
> + ofputil_put_OFPAT10_SET_VLAN_PCP(out)->vlan_pcp
> + = ofpact_get_SET_VLAN_PCP(a)->vlan_pcp;
> + break;
> +
> + case OFPACT_STRIP_VLAN:
> + ofputil_put_OFPAT10_STRIP_VLAN(out);
> + break;
> +
> + case OFPACT_SET_ETH_SRC:
> + memcpy(ofputil_put_OFPAT10_SET_DL_SRC(out)->dl_addr,
> + ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN);
> + break;
> +
> + case OFPACT_SET_ETH_DST:
> + memcpy(ofputil_put_OFPAT10_SET_DL_DST(out)->dl_addr,
> + ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN);
> + break;
> +
> + case OFPACT_SET_IPV4_SRC:
> + ofputil_put_OFPAT10_SET_NW_SRC(out)->nw_addr
> + = ofpact_get_SET_IPV4_SRC(a)->ipv4;
> + break;
> +
> + case OFPACT_SET_IPV4_DST:
> + ofputil_put_OFPAT10_SET_NW_DST(out)->nw_addr
> + = ofpact_get_SET_IPV4_DST(a)->ipv4;
> + break;
> +
> + case OFPACT_SET_IPV4_DSCP:
> + ofputil_put_OFPAT10_SET_NW_TOS(out)->nw_tos
> + = ofpact_get_SET_IPV4_DSCP(a)->dscp;
> + break;
> +
> + case OFPACT_SET_L4_SRC_PORT:
> + ofputil_put_OFPAT10_SET_TP_SRC(out)->tp_port
> + = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
> + break;
> +
> + case OFPACT_SET_L4_DST_PORT:
> + ofputil_put_OFPAT10_SET_TP_DST(out)->tp_port
> + = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
> + break;
> +
> + case OFPACT_CONTROLLER:
> + case OFPACT_OUTPUT_REG:
> + case OFPACT_BUNDLE:
> + case OFPACT_REG_MOVE:
> + case OFPACT_REG_LOAD:
> + case OFPACT_DEC_TTL:
> + case OFPACT_SET_TUNNEL:
> + case OFPACT_SET_QUEUE:
> + case OFPACT_POP_QUEUE:
> + case OFPACT_FIN_TIMEOUT:
> + case OFPACT_RESUBMIT:
> + case OFPACT_LEARN:
> + case OFPACT_MULTIPATH:
> + case OFPACT_AUTOPATH:
> + case OFPACT_NOTE:
> + case OFPACT_EXIT:
> + ofpact_to_nxast(a, out);
> + break;
> + }
> +}
> +
> +/* Converts the ofpacts in 'ofpacts' (terminated by OFPACT_END) into OpenFlow
> + * actions in 'openflow', appending the actions to any existing data in
> + * 'openflow'. */
> +void
> +ofpacts_to_openflow(const struct ofpact ofpacts[], struct ofpbuf *openflow)
> +{
> + const struct ofpact *a;
> +
> + OFPACT_FOR_EACH (a, ofpacts) {
> + ofpact_to_openflow10(a, openflow);
> + }
> +}
> +
> +/* Returns true if 'action' outputs to 'port', false otherwise. */
> +static bool
> +ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
> +{
> + switch (ofpact->type) {
> + case OFPACT_OUTPUT:
> + return ofpact_get_OUTPUT(ofpact)->port == port;
> + case OFPACT_ENQUEUE:
> + return ofpact_get_ENQUEUE(ofpact)->port == port;
> + case OFPACT_CONTROLLER:
> + return port == OFPP_CONTROLLER;
> +
> + case OFPACT_END:
> + case OFPACT_OUTPUT_REG:
> + case OFPACT_BUNDLE:
> + case OFPACT_SET_VLAN_VID:
> + case OFPACT_SET_VLAN_PCP:
> + case OFPACT_STRIP_VLAN:
> + case OFPACT_SET_ETH_SRC:
> + case OFPACT_SET_ETH_DST:
> + case OFPACT_SET_IPV4_SRC:
> + case OFPACT_SET_IPV4_DST:
> + case OFPACT_SET_IPV4_DSCP:
> + case OFPACT_SET_L4_SRC_PORT:
> + case OFPACT_SET_L4_DST_PORT:
> + case OFPACT_REG_MOVE:
> + case OFPACT_REG_LOAD:
> + case OFPACT_DEC_TTL:
> + case OFPACT_SET_TUNNEL:
> + case OFPACT_SET_QUEUE:
> + case OFPACT_POP_QUEUE:
> + case OFPACT_FIN_TIMEOUT:
> + case OFPACT_RESUBMIT:
> + case OFPACT_LEARN:
> + case OFPACT_MULTIPATH:
> + case OFPACT_AUTOPATH:
> + case OFPACT_NOTE:
> + case OFPACT_EXIT:
> + default:
> + return false;
> + }
> +}
> +
> +/* Returns true if any action in 'ofpacts' outputs to 'port', false
> + * otherwise. */
> +bool
> +ofpacts_output_to_port(const struct ofpact *ofpacts, uint16_t port)
> +{
> + const struct ofpact *a;
> +
> + OFPACT_FOR_EACH (a, ofpacts) {
> + if (ofpact_outputs_to_port(a, port)) {
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +bool
> +ofpacts_equal(const struct ofpact *a, size_t a_len,
> + const struct ofpact *b, size_t b_len)
> +{
> + return a_len == b_len && !memcmp(a, b, a_len);
> +}
> +
> +/* Formatting ofpacts. */
> +
> +static void
> +print_note(const struct ofpact_note *note, struct ds *string)
> +{
> + size_t i;
> +
> + ds_put_cstr(string, "note:");
> + for (i = 0; i < note->length; i++) {
> + if (i) {
> + ds_put_char(string, '.');
> + }
> + ds_put_format(string, "%02"PRIx8, note->data[i]);
> + }
> +}
> +
> +static void
> +print_fin_timeout(const struct ofpact_fin_timeout *fin_timeout,
> + struct ds *s)
> +{
> + ds_put_cstr(s, "fin_timeout(");
> + if (fin_timeout->fin_idle_timeout) {
> + ds_put_format(s, "idle_timeout=%"PRIu16",",
> + fin_timeout->fin_idle_timeout);
> + }
> + if (fin_timeout->fin_hard_timeout) {
> + ds_put_format(s, "hard_timeout=%"PRIu16",",
> + fin_timeout->fin_hard_timeout);
> + }
> + ds_chomp(s, ',');
> + ds_put_char(s, ')');
> +}
> +
> +static void
> +ofpact_format(const struct ofpact *a, struct ds *s)
> +{
> + const struct ofpact_enqueue *enqueue;
> + const struct ofpact_resubmit *resubmit;
> + const struct ofpact_autopath *autopath;
> + const struct ofpact_controller *controller;
> + const struct ofpact_tunnel *tunnel;
> + uint16_t port;
> +
> + switch (a->type) {
> + case OFPACT_END:
> + NOT_REACHED();
> +
> + case OFPACT_OUTPUT:
> + port = ofpact_get_OUTPUT(a)->port;
> + if (port < OFPP_MAX) {
> + ds_put_format(s, "output:%"PRIu16, port);
> + } else {
> + ofputil_format_port(port, s);
> + if (port == OFPP_CONTROLLER) {
> + ds_put_format(s, ":%"PRIu16, ofpact_get_OUTPUT(a)->max_len);
> + }
> + }
> + break;
> +
> + case OFPACT_CONTROLLER:
> + controller = ofpact_get_CONTROLLER(a);
> + if (controller->reason == OFPR_ACTION &&
> + controller->controller_id == 0) {
> + ds_put_format(s, "CONTROLLER:%"PRIu16,
> + ofpact_get_CONTROLLER(a)->max_len);
> + } else {
> + enum ofp_packet_in_reason reason = controller->reason;
> +
> + ds_put_cstr(s, "controller(");
> + if (reason != OFPR_ACTION) {
> + ds_put_format(s, "reason=%s,",
> + ofputil_packet_in_reason_to_string(reason));
> + }
> + if (controller->max_len != UINT16_MAX) {
> + ds_put_format(s, "max_len=%"PRIu16",", controller->max_len);
> + }
> + if (controller->controller_id != 0) {
> + ds_put_format(s, "id=%"PRIu16",", controller->controller_id);
> + }
> + ds_chomp(s, ',');
> + ds_put_char(s, ')');
> + }
> + break;
> +
> + case OFPACT_ENQUEUE:
> + enqueue = ofpact_get_ENQUEUE(a);
> + ds_put_format(s, "enqueue:");
> + ofputil_format_port(enqueue->port, s);
> + ds_put_format(s, "q%"PRIu32, enqueue->queue);
> + break;
> +
> + case OFPACT_OUTPUT_REG:
> + ds_put_cstr(s, "output:");
> + mf_format_subfield(&ofpact_get_OUTPUT_REG(a)->src, s);
> + break;
> +
> + case OFPACT_BUNDLE:
> + bundle_format(ofpact_get_BUNDLE(a), s);
> + break;
> +
> + case OFPACT_SET_VLAN_VID:
> + ds_put_format(s, "mod_vlan_vid:%"PRIu16,
> + ofpact_get_SET_VLAN_VID(a)->vlan_vid);
> + break;
> +
> + case OFPACT_SET_VLAN_PCP:
> + ds_put_format(s, "mod_vlan_pcp:%"PRIu8,
> + ofpact_get_SET_VLAN_PCP(a)->vlan_pcp);
> + break;
> +
> + case OFPACT_STRIP_VLAN:
> + ds_put_cstr(s, "strip_vlan");
> + break;
> +
> + case OFPACT_SET_ETH_SRC:
> + ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac));
> + break;
> +
> + case OFPACT_SET_ETH_DST:
> + ds_put_format(s, "mod_dl_dst:"ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(ofpact_get_SET_ETH_DST(a)->mac));
> + break;
> +
> + case OFPACT_SET_IPV4_SRC:
> + ds_put_format(s, "mod_nw_src:"IP_FMT,
> + IP_ARGS(&ofpact_get_SET_IPV4_SRC(a)->ipv4));
> + break;
> +
> + case OFPACT_SET_IPV4_DST:
> + ds_put_format(s, "mod_nw_dst:"IP_FMT,
> + IP_ARGS(&ofpact_get_SET_IPV4_DST(a)->ipv4));
> + break;
> +
> + case OFPACT_SET_IPV4_DSCP:
> + ds_put_format(s, "mod_nw_tos:%d", ofpact_get_SET_IPV4_DSCP(a)->dscp);
> + break;
> +
> + case OFPACT_SET_L4_SRC_PORT:
> + ds_put_format(s, "mod_tp_src:%d", ofpact_get_SET_L4_SRC_PORT(a)->port);
> + break;
> +
> + case OFPACT_SET_L4_DST_PORT:
> + ds_put_format(s, "mod_tp_dst:%d", ofpact_get_SET_L4_DST_PORT(a)->port);
> + break;
> +
> + case OFPACT_REG_MOVE:
> + nxm_format_reg_move(ofpact_get_REG_MOVE(a), s);
> + break;
> +
> + case OFPACT_REG_LOAD:
> + nxm_format_reg_load(ofpact_get_REG_LOAD(a), s);
> + break;
> +
> + case OFPACT_DEC_TTL:
> + ds_put_cstr(s, "dec_ttl");
> + break;
> +
> + case OFPACT_SET_TUNNEL:
> + tunnel = ofpact_get_SET_TUNNEL(a);
> + ds_put_format(s, "set_tunnel%s:%#"PRIx64,
> + (tunnel->tun_id > UINT32_MAX
> + || a->compat == OFPUTIL_NXAST_SET_TUNNEL64 ? "64" : ""),
> + tunnel->tun_id);
> + break;
> +
> + case OFPACT_SET_QUEUE:
> + ds_put_format(s, "set_queue:%"PRIu32,
> + ofpact_get_SET_QUEUE(a)->queue_id);
> + break;
> +
> + case OFPACT_POP_QUEUE:
> + ds_put_cstr(s, "pop_queue");
> + break;
> +
> + case OFPACT_FIN_TIMEOUT:
> + print_fin_timeout(ofpact_get_FIN_TIMEOUT(a), s);
> + break;
> +
> + case OFPACT_RESUBMIT:
> + resubmit = ofpact_get_RESUBMIT(a);
> + if (resubmit->in_port != OFPP_IN_PORT && resubmit->table_id == 255) {
> + ds_put_format(s, "resubmit:%"PRIu16, resubmit->in_port);
> + } else {
> + ds_put_format(s, "resubmit(");
> + if (resubmit->in_port != OFPP_IN_PORT) {
> + ofputil_format_port(resubmit->in_port, s);
> + }
> + ds_put_char(s, ',');
> + if (resubmit->table_id != 255) {
> + ds_put_format(s, "%"PRIu8, resubmit->table_id);
> + }
> + ds_put_char(s, ')');
> + }
> + break;
> +
> + case OFPACT_LEARN:
> + learn_format(ofpact_get_LEARN(a), s);
> + break;
> +
> + case OFPACT_MULTIPATH:
> + multipath_format(ofpact_get_MULTIPATH(a), s);
> + break;
> +
> + case OFPACT_AUTOPATH:
> + autopath = ofpact_get_AUTOPATH(a);
> + ds_put_format(s, "autopath(%u,", autopath->port);
> + mf_format_subfield(&autopath->dst, s);
> + ds_put_char(s, ')');
> + break;
> +
> + case OFPACT_NOTE:
> + print_note(ofpact_get_NOTE(a), s);
> + break;
> +
> + case OFPACT_EXIT:
> + ds_put_cstr(s, "exit");
> + break;
> + }
> +}
> +
> +/* Appends a string representing the actions in 'ofpacts' (terminated by
> + * OFPACT_END) to 'string'. */
> +void
> +ofpacts_format(const struct ofpact *ofpacts, struct ds *string)
> +{
> + ds_put_cstr(string, "actions=");
> + if (ofpacts->type == OFPACT_END) {
> + ds_put_cstr(string, "drop");
> + } else {
> + const struct ofpact *a;
> +
> + OFPACT_FOR_EACH (a, ofpacts) {
> + if (a != ofpacts) {
> + ds_put_cstr(string, ",");
> + }
> + ofpact_format(a, string);
> + }
> + }
> +}
> +
> +/* Internal use by helpers. */
> +
> +void *
> +ofpact_put(struct ofpbuf *ofpacts, enum ofpact_type type, size_t len)
> +{
> + struct ofpact *ofpact;
> + unsigned int rem;
> +
> + rem = ofpacts->size % OFPACT_ALIGNTO;
> + if (rem) {
> + ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem);
> + }
> +
> + ofpact = ofpacts->l2 = ofpbuf_put_uninit(ofpacts, len);
> + ofpact_init(ofpact, type, len);
> + return ofpact;
> +}
> +
> +void
> +ofpact_init(struct ofpact *ofpact, enum ofpact_type type, size_t len)
> +{
> + memset(ofpact, 0, len);
> + ofpact->type = type;
> + ofpact->compat = OFPUTIL_ACTION_INVALID;
> + ofpact->len = len;
> +}
> +
> +/* Updates 'ofpact->len' to the number of bytes in the tail of 'ofpacts'
> + * starting at 'ofpact'.
> + *
> + * This is the correct way to update a variable-length ofpact's length after
> + * adding the variable-length part of the payload. (See the large comment
> + * near the end of ofp-actions.h for more information.) */
> +void
> +ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
> +{
> + assert(ofpact == ofpacts->l2);
> + ofpact->len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact;
> +}
> diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
> new file mode 100644
> index 0000000..7db01a5
> --- /dev/null
> +++ b/lib/ofp-actions.h
> @@ -0,0 +1,479 @@
> +/*
> + * Copyright (c) 2012 Nicira Networks.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef OFP_ACTIONS_H
> +#define OFP_ACTIONS_H 1
> +
> +#include <stdint.h>
> +#include "meta-flow.h"
> +#include "ofp-errors.h"
> +#include "ofp-util.h"
> +#include "openflow/openflow.h"
> +#include "openflow/nicira-ext.h"
> +#include "openvswitch/types.h"
> +
> +/* List of OVS abstracted actions.
> + *
> + * This macro is used directly only internally by this header, but the list is
> + * still of interest to developers.
> + *
> + * Each DEFINE_OFPACT invocation has the following parameters:
> + *
> + * 1. <ENUM>, used below in the enum definition of OFPACT_<ENUM>, and
> + * elsewhere.
> + *
> + * 2. <STRUCT> corresponding to a structure "struct <STRUCT>", that must be
> + * defined below. This structure must be an abstract definition of the
> + * action. Its first member must have type "struct ofpact" and name
> + * "ofpact". It may be fixed length or end with a flexible array member
> + * (e.g. "int member[];").
> + *
> + * 3. <MEMBER>, which has one of two possible values:
> + *
> + * - If "struct <STRUCT>" is fixed-length, it must be "ofpact".
> + *
> + * - If "struct <STRUCT>" is variable-length, it must be the name of the
> + * flexible array member.
> + */
> +#define OFPACTS \
> + /* Sentinel. */ \
> + DEFINE_OFPACT(END, ofpact_null, ofpact) \
> + \
> + /* Output. */ \
> + DEFINE_OFPACT(OUTPUT, ofpact_output, ofpact) \
> + DEFINE_OFPACT(CONTROLLER, ofpact_controller, ofpact) \
> + DEFINE_OFPACT(ENQUEUE, ofpact_enqueue, ofpact) \
> + DEFINE_OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact) \
> + DEFINE_OFPACT(BUNDLE, ofpact_bundle, slaves) \
> + \
> + /* Header changes. */ \
> + DEFINE_OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact) \
> + DEFINE_OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact) \
> + DEFINE_OFPACT(STRIP_VLAN, ofpact_null, ofpact) \
> + DEFINE_OFPACT(SET_ETH_SRC, ofpact_mac, ofpact) \
> + DEFINE_OFPACT(SET_ETH_DST, ofpact_mac, ofpact) \
> + DEFINE_OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact) \
> + DEFINE_OFPACT(SET_IPV4_DST, ofpact_ipv4, ofpact) \
> + DEFINE_OFPACT(SET_IPV4_DSCP, ofpact_dscp, ofpact) \
> + DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port, ofpact) \
> + DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port, ofpact) \
> + DEFINE_OFPACT(REG_MOVE, ofpact_reg_move, ofpact) \
> + DEFINE_OFPACT(REG_LOAD, ofpact_reg_load, ofpact) \
> + DEFINE_OFPACT(DEC_TTL, ofpact_null, ofpact) \
> + \
> + /* Metadata. */ \
> + DEFINE_OFPACT(SET_TUNNEL, ofpact_tunnel, ofpact) \
> + DEFINE_OFPACT(SET_QUEUE, ofpact_queue, ofpact) \
> + DEFINE_OFPACT(POP_QUEUE, ofpact_null, ofpact) \
> + DEFINE_OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact) \
> + \
> + /* Flow table interaction. */ \
> + DEFINE_OFPACT(RESUBMIT, ofpact_resubmit, ofpact) \
> + DEFINE_OFPACT(LEARN, ofpact_learn, specs) \
> + \
> + /* Arithmetic. */ \
> + DEFINE_OFPACT(MULTIPATH, ofpact_multipath, ofpact) \
> + DEFINE_OFPACT(AUTOPATH, ofpact_autopath, ofpact) \
> + \
> + /* Other. */ \
> + DEFINE_OFPACT(NOTE, ofpact_note, data) \
> + DEFINE_OFPACT(EXIT, ofpact_null, ofpact)
> +
> +/* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
> +enum OVS_PACKED_ENUM ofpact_type {
> +#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) OFPACT_##ENUM,
> + OFPACTS
> +#undef DEFINE_OFPACT
> +};
> +
> +/* N_OFPACTS, the number of values of "enum ofpact_type". */
> +enum {
> + N_OFPACTS =
> +#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) + 1
> + OFPACTS
> +#undef DEFINE_OFPACT
> +};
> +
> +/* Header for an action.
> + *
> + * Each action is a structure "struct ofpact_*" that begins with "struct
> + * ofpact", usually followed by other data that describes the action. Actions
> + * are padded out to a multiple of OFPACT_ALIGNTO bytes in length. */
> +struct ofpact {
> + enum ofpact_type type; /* OFPACT_*. */
> + enum ofputil_action_code compat; /* Original type when added, if any. */
> + uint16_t len; /* Length of the action, in bytes, including
> + * struct ofpact, excluding padding. */
> +};
> +
> +#ifdef __GNUC__
> +/* Make sure that OVS_PACKED_ENUM really worked. */
> +BUILD_ASSERT_DECL(sizeof(struct ofpact) == 4);
> +#endif
> +
> +/* Alignment. */
> +#define OFPACT_ALIGNTO 8
> +#define OFPACT_ALIGN(SIZE) ROUND_UP(SIZE, OFPACT_ALIGNTO)
> +
> +static inline struct ofpact *
> +ofpact_next(const struct ofpact *ofpact)
> +{
> + return (void *) ((uint8_t *) ofpact + OFPACT_ALIGN(ofpact->len));
> +}
> +
> +/* Assigns POS to each action starting at OFPACTS in turn, assuming that the
> + * set of actions is terminated by OFPACT_END. */
> +#define OFPACT_FOR_EACH(POS, OFPACTS) \
> + for ((POS) = (OFPACTS); (POS)->type != OFPACT_END; \
> + (POS) = ofpact_next(POS))
> +
> +/* Action structure for each OFPACT_*. */
> +
> +/* OFPACT_END, OFPACT_STRIP_VLAN, OFPACT_DEC_TTL, OFPACT_POP_QUEUE,
> + * OFPACT_EXIT.
> + *
> + * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_POP_QUEUE, NXAST_EXIT.
> + *
> + * Action structure for actions that do not have any extra data beyond the
> + * action type. */
> +struct ofpact_null {
> + struct ofpact ofpact;
> +};
> +
> +/* OFPACT_OUTPUT.
> + *
> + * Used for OFPAT10_OUTPUT. */
> +struct ofpact_output {
> + struct ofpact ofpact;
> + uint16_t port; /* Output port. */
> + uint16_t max_len; /* Max send len, for port OFPP_CONTROLLER. */
> +};
> +
> +/* OFPACT_CONTROLLER.
> + *
> + * Used for NXAST_CONTROLLER. */
> +struct ofpact_controller {
> + struct ofpact ofpact;
> + uint16_t max_len; /* Maximum length to send to controller. */
> + uint16_t controller_id; /* Controller ID to send packet-in. */
> + enum ofp_packet_in_reason reason; /* Reason to put in packet-in. */
> +};
> +
> +/* OFPACT_ENQUEUE.
> + *
> + * Used for OFPAT10_ENQUEUE. */
> +struct ofpact_enqueue {
> + struct ofpact ofpact;
> + uint16_t port;
> + uint32_t queue;
> +};
> +
> +/* OFPACT_OUTPUT_REG.
> + *
> + * Used for NXAST_OUTPUT_REG. */
> +struct ofpact_output_reg {
> + struct ofpact ofpact;
> + struct mf_subfield src;
> + uint16_t max_len;
> +};
> +
> +/* OFPACT_BUNDLE.
> + *
> + * Used for NXAST_BUNDLE. */
> +struct ofpact_bundle {
> + struct ofpact ofpact;
> +
> + /* Slave choice algorithm to apply to hash value. */
> + enum nx_bd_algorithm algorithm;
> +
> + /* What fields to hash and how. */
> + enum nx_hash_fields fields;
> + uint16_t basis; /* Universal hash parameter. */
> +
> + struct mf_subfield dst;
> +
> + /* Slaves for output. */
> + unsigned int n_slaves;
> + uint16_t slaves[];
> +};
> +
> +/* OFPACT_SET_VLAN_VID.
> + *
> + * Used for OFPAT10_SET_VLAN_VID. */
> +struct ofpact_vlan_vid {
> + struct ofpact ofpact;
> + uint16_t vlan_vid; /* VLAN VID in low 12 bits, 0 in other bits. */
> +};
> +
> +/* OFPACT_SET_VLAN_PCP.
> + *
> + * Used for OFPAT10_SET_VLAN_PCP. */
> +struct ofpact_vlan_pcp {
> + struct ofpact ofpact;
> + uint8_t vlan_pcp; /* VLAN PCP in low 3 bits, 0 in other bits. */
> +};
> +
> +/* OFPACT_SET_ETH_SRC, OFPACT_SET_ETH_DST.
> + *
> + * Used for OFPAT10_SET_DL_SRC, OFPAT10_SET_DL_DST. */
> +struct ofpact_mac {
> + struct ofpact ofpact;
> + uint8_t mac[ETH_ADDR_LEN];
> +};
> +
> +/* OFPACT_SET_IPV4_SRC, OFPACT_SET_IPV4_DST.
> + *
> + * Used for OFPAT10_SET_NW_SRC, OFPAT10_SET_NW_DST. */
> +struct ofpact_ipv4 {
> + struct ofpact ofpact;
> + ovs_be32 ipv4;
> +};
> +
> +/* OFPACT_SET_IPV4_DSCP.
> + *
> + * Used for OFPAT10_SET_NW_TOS. */
> +struct ofpact_dscp {
> + struct ofpact ofpact;
> + uint8_t dscp; /* DSCP in high 6 bits, rest ignored. */
> +};
> +
> +/* OFPACT_SET_L4_SRC_PORT, OFPACT_SET_L4_DST_PORT.
> + *
> + * Used for OFPAT10_SET_TP_SRC, OFPAT10_SET_TP_DST. */
> +struct ofpact_l4_port {
> + struct ofpact ofpact;
> + uint16_t port; /* TCP or UDP port number. */
> +};
> +
> +/* OFPACT_REG_MOVE.
> + *
> + * Used for NXAST_REG_MOVE. */
> +struct ofpact_reg_move {
> + struct ofpact ofpact;
> + struct mf_subfield src;
> + struct mf_subfield dst;
> +};
> +
> +/* OFPACT_REG_LOAD.
> + *
> + * Used for NXAST_REG_LOAD. */
> +struct ofpact_reg_load {
> + struct ofpact ofpact;
> + struct mf_subfield dst;
> + uint64_t value;
> +};
> +
> +/* OFPACT_SET_TUNNEL.
> + *
> + * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */
> +struct ofpact_tunnel {
> + struct ofpact ofpact;
> + uint64_t tun_id;
> +};
> +
> +/* OFPACT_SET_QUEUE.
> + *
> + * Used for NXAST_SET_QUEUE. */
> +struct ofpact_queue {
> + struct ofpact ofpact;
> + uint32_t queue_id;
> +};
> +
> +/* OFPACT_FIN_TIMEOUT.
> + *
> + * Used for NXAST_FIN_TIMEOUT. */
> +struct ofpact_fin_timeout {
> + struct ofpact ofpact;
> + uint16_t fin_idle_timeout;
> + uint16_t fin_hard_timeout;
> +};
> +
> +/* OFPACT_RESUBMIT.
> + *
> + * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
> +struct ofpact_resubmit {
> + struct ofpact ofpact;
> + uint16_t in_port;
> + uint8_t table_id;
> +};
> +
> +/* Part of struct ofpact_learn, below. */
> +struct ofpact_learn_spec {
> + int n_bits;
> +
> + int src_type;
> + struct mf_subfield src;
> + union mf_subvalue src_imm;
> +
> + int dst_type;
> + struct mf_subfield dst;
> +};
> +
> +/* OFPACT_LEARN.
> + *
> + * Used for NXAST_LEARN. */
> +struct ofpact_learn {
> + struct ofpact ofpact;
> +
> + uint16_t idle_timeout; /* Idle time before discarding (seconds). */
> + uint16_t hard_timeout; /* Max time before discarding (seconds). */
> + uint16_t priority; /* Priority level of flow entry. */
> + uint64_t cookie; /* Cookie for new flow. */
> + uint16_t flags; /* Either 0 or OFPFF_SEND_FLOW_REM. */
> + uint8_t table_id; /* Table to insert flow entry. */
> + uint16_t fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */
> + uint16_t fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */
> +
> + unsigned int n_specs;
> + struct ofpact_learn_spec specs[];
> +};
> +
> +/* OFPACT_MULTIPATH.
> + *
> + * Used for NXAST_MULTIPATH. */
> +struct ofpact_multipath {
> + struct ofpact ofpact;
> +
> + /* What fields to hash and how. */
> + enum nx_hash_fields fields;
> + uint16_t basis; /* Universal hash parameter. */
> +
> + /* Multipath link choice algorithm to apply to hash value. */
> + enum nx_mp_algorithm algorithm;
> + uint16_t max_link; /* Number of output links, minus 1. */
> + uint32_t arg; /* Algorithm-specific argument. */
> +
> + /* Where to store the result. */
> + struct mf_subfield dst;
> +};
> +
> +/* OFPACT_AUTOPATH.
> + *
> + * Used for NXAST_AUTOPATH. */
> +struct ofpact_autopath {
> + struct ofpact ofpact;
> + struct mf_subfield dst;
> + uint32_t port;
> +};
> +
> +/* OFPACT_NOTE.
> + *
> + * Used for NXAST_NOTE. */
> +struct ofpact_note {
> + struct ofpact ofpact;
> + size_t length;
> + uint8_t data[];
> +};
> +
> +/* Converting OpenFlow to ofpacts. */
> +enum ofperr ofpacts_pull_openflow(struct ofpbuf *openflow,
> + unsigned int actions_len,
> + struct ofpbuf *ofpacts);
> +enum ofperr ofpacts_check(const struct ofpact[],
> + const struct flow *, int max_ports);
> +
> +/* Converting ofpacts to OpenFlow. */
> +void ofpacts_to_openflow(const struct ofpact[], struct ofpbuf *openflow);
> +
> +/* Working with ofpacts. */
> +bool ofpacts_output_to_port(const struct ofpact[], uint16_t port);
> +bool ofpacts_equal(const struct ofpact a[], size_t a_len,
> + const struct ofpact b[], size_t b_len);
> +
> +/* Formatting ofpacts.
> + *
> + * (For parsing ofpacts, see ofp-parse.h.) */
> +void ofpacts_format(const struct ofpact[], struct ds *);
> +
> +/* Internal use by the helpers below. */
> +void ofpact_init(struct ofpact *, enum ofpact_type, size_t len);
> +void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len);
> +
> +/* For each OFPACT_<ENUM> with a corresponding struct <STRUCT>, this defines
> + * the following commonly useful functions:
> + *
> + * struct <STRUCT> *ofpact_put_<ENUM>(struct ofpbuf *ofpacts);
> + *
> + * Appends a new 'ofpact', of length OFPACT_<ENUM>_RAW_SIZE, to 'ofpacts',
> + * initializes it with ofpact_init_<ENUM>(), and returns it. Also sets
> + * 'ofpacts->l2' to the returned action.
> + *
> + * After using this function to add a variable-length action, add the
> + * elements of the flexible array (e.g. with ofpbuf_put()), then use
> + * ofpact_update_len() to update the length embedded into the action.
> + * (Keep in mind the need to refresh the structure from 'ofpacts->l2' after
> + * adding data to 'ofpacts'.)
> + *
> + * struct <STRUCT> *ofpact_get_<ENUM>(const struct ofpact *ofpact);
> + *
> + * Returns 'ofpact' cast to "struct <STRUCT> *". 'ofpact->type' must be
> + * OFPACT_<ENUM>.
> + *
> + * as well as the following more rarely useful definitions:
> + *
> + * void ofpact_init_<ENUM>(struct <STRUCT> *ofpact);
> + *
> + * Initializes the parts of 'ofpact' that identify it as having type
> + * OFPACT_<ENUM> and length OFPACT_<ENUM>_RAW_SIZE and zeros the rest.
> + *
> + * <ENUM>_RAW_SIZE
> + *
> + * The size of the action structure. For a fixed-length action, this is
> + * sizeof(struct <STRUCT>). For a variable-length action, this is the
> + * offset to the variable-length part.
> + *
> + * <ENUM>_SIZE
> + *
> + * An integer constant, the value of OFPACT_<ENUM>_RAW_SIZE rounded up to a
> + * multiple of OFPACT_ALIGNTO.
> + */
> +#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) \
> + BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0); \
> + \
> + enum { OFPACT_##ENUM##_RAW_SIZE \
> + = (offsetof(struct STRUCT, MEMBER) \
> + ? offsetof(struct STRUCT, MEMBER) \
> + : sizeof(struct STRUCT)) }; \
> + \
> + enum { OFPACT_##ENUM##_SIZE \
> + = ROUND_UP(OFPACT_##ENUM##_RAW_SIZE, OFPACT_ALIGNTO) }; \
> + \
> + static inline struct STRUCT * \
> + ofpact_get_##ENUM(const struct ofpact *ofpact) \
> + { \
> + assert(ofpact->type == OFPACT_##ENUM); \
> + return (struct STRUCT *) ofpact; \
> + } \
> + \
> + static inline struct STRUCT * \
> + ofpact_put_##ENUM(struct ofpbuf *ofpacts) \
> + { \
> + return ofpact_put(ofpacts, OFPACT_##ENUM, \
> + OFPACT_##ENUM##_RAW_SIZE); \
> + } \
> + \
> + static inline void \
> + ofpact_init_##ENUM(struct STRUCT *ofpact) \
> + { \
> + ofpact_init(&ofpact->ofpact, OFPACT_##ENUM, \
> + OFPACT_##ENUM##_RAW_SIZE); \
> + }
> +OFPACTS
> +#undef DEFINE_OFPACT
> +
> +void ofpact_update_len(struct ofpbuf *, struct ofpact *);
> +
> +#endif /* ofp-actions.h */
> diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
> index 1d331bb..ae70fb5 100644
> --- a/lib/ofp-parse.c
> +++ b/lib/ofp-parse.c
> @@ -28,9 +28,10 @@
> #include "dynamic-string.h"
> #include "learn.h"
> #include "meta-flow.h"
> -#include "netdev.h"
> #include "multipath.h"
> +#include "netdev.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> #include "openflow/openflow.h"
> @@ -122,107 +123,73 @@ str_to_ip(const char *str, ovs_be32 *ip)
> *ip = in_addr.s_addr;
> }
>
> -static struct ofp_action_output *
> -put_output_action(struct ofpbuf *b, uint16_t port)
> -{
> - struct ofp_action_output *oao;
> -
> - oao = ofputil_put_OFPAT10_OUTPUT(b);
> - oao->port = htons(port);
> - return oao;
> -}
> -
> static void
> -parse_enqueue(struct ofpbuf *b, char *arg)
> +parse_enqueue(char *arg, struct ofpbuf *ofpacts)
> {
> char *sp = NULL;
> char *port = strtok_r(arg, ":q", &sp);
> char *queue = strtok_r(NULL, "", &sp);
> - struct ofp_action_enqueue *oae;
> + struct ofpact_enqueue *enqueue;
>
> if (port == NULL || queue == NULL) {
> ovs_fatal(0, "\"enqueue\" syntax is \"enqueue:PORT:QUEUE\"");
> }
>
> - oae = ofputil_put_OFPAT10_ENQUEUE(b);
> - oae->port = htons(str_to_u32(port));
> - oae->queue_id = htonl(str_to_u32(queue));
> + enqueue = ofpact_put_ENQUEUE(ofpacts);
> + enqueue->port = str_to_u32(port);
> + enqueue->queue = str_to_u32(queue);
> }
>
> static void
> -parse_output(struct ofpbuf *b, char *arg)
> +parse_output(char *arg, struct ofpbuf *ofpacts)
> {
> if (strchr(arg, '[')) {
> - struct nx_action_output_reg *naor;
> - struct mf_subfield src;
> -
> - mf_parse_subfield(&src, arg);
> + struct ofpact_output_reg *output_reg;
>
> - naor = ofputil_put_NXAST_OUTPUT_REG(b);
> - naor->ofs_nbits = nxm_encode_ofs_nbits(src.ofs, src.n_bits);
> - naor->src = htonl(src.field->nxm_header);
> - naor->max_len = htons(UINT16_MAX);
> + output_reg = ofpact_put_OUTPUT_REG(ofpacts);
> + mf_parse_subfield(&output_reg->src, arg);
> + output_reg->max_len = UINT16_MAX;
> } else {
> - put_output_action(b, str_to_u32(arg));
> + struct ofpact_output *output;
> +
> + output = ofpact_put_OUTPUT(ofpacts);
> + output->port = str_to_u32(arg);
> + output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0;
> }
> }
>
> static void
> -parse_resubmit(struct ofpbuf *b, char *arg)
> +parse_resubmit(char *arg, struct ofpbuf *ofpacts)
> {
> - struct nx_action_resubmit *nar;
> + struct ofpact_resubmit *resubmit;
> char *in_port_s, *table_s;
> - uint16_t in_port;
> - uint8_t table;
> +
> + resubmit = ofpact_put_RESUBMIT(ofpacts);
>
> in_port_s = strsep(&arg, ",");
> if (in_port_s && in_port_s[0]) {
> - if (!ofputil_port_from_string(in_port_s, &in_port)) {
> - in_port = str_to_u32(in_port_s);
> + if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) {
> + resubmit->in_port = str_to_u32(in_port_s);
> }
> } else {
> - in_port = OFPP_IN_PORT;
> + resubmit->in_port = OFPP_IN_PORT;
> }
>
> table_s = strsep(&arg, ",");
> - table = table_s && table_s[0] ? str_to_u32(table_s) : 255;
> + resubmit->table_id = table_s && table_s[0] ? str_to_u32(table_s) : 255;
>
> - if (in_port == OFPP_IN_PORT && table == 255) {
> + if (resubmit->in_port == OFPP_IN_PORT && resubmit->table_id == 255) {
> ovs_fatal(0, "at least one \"in_port\" or \"table\" must be specified "
> " on resubmit");
> }
> -
> - if (in_port != OFPP_IN_PORT && table == 255) {
> - nar = ofputil_put_NXAST_RESUBMIT(b);
> - } else {
> - nar = ofputil_put_NXAST_RESUBMIT_TABLE(b);
> - nar->table = table;
> - }
> - nar->in_port = htons(in_port);
> -}
> -
> -static void
> -parse_set_tunnel(struct ofpbuf *b, const char *arg)
> -{
> - uint64_t tun_id = str_to_u64(arg);
> - if (tun_id > UINT32_MAX) {
> - ofputil_put_NXAST_SET_TUNNEL64(b)->tun_id = htonll(tun_id);
> - } else {
> - ofputil_put_NXAST_SET_TUNNEL(b)->tun_id = htonl(tun_id);
> - }
> }
>
> static void
> -parse_note(struct ofpbuf *b, const char *arg)
> +parse_note(const char *arg, struct ofpbuf *ofpacts)
> {
> - size_t start_ofs = b->size;
> - struct nx_action_note *nan;
> - int remainder;
> - size_t len;
> + struct ofpact_note *note;
>
> - nan = ofputil_put_NXAST_NOTE(b);
> -
> - b->size -= sizeof nan->note;
> + note = ofpact_put_NOTE(ofpacts);
> while (*arg != '\0') {
> uint8_t byte;
> bool ok;
> @@ -238,32 +205,27 @@ parse_note(struct ofpbuf *b, const char *arg)
> if (!ok) {
> ovs_fatal(0, "bad hex digit in `note' argument");
> }
> - ofpbuf_put(b, &byte, 1);
> + ofpbuf_put(ofpacts, &byte, 1);
>
> - arg += 2;
> - }
> + note = ofpacts->l2;
> + note->length++;
>
> - len = b->size - start_ofs;
> - remainder = len % OFP_ACTION_ALIGN;
> - if (remainder) {
> - ofpbuf_put_zeros(b, OFP_ACTION_ALIGN - remainder);
> + arg += 2;
> }
> - nan = (struct nx_action_note *)((char *)b->data + start_ofs);
> - nan->len = htons(b->size - start_ofs);
> + ofpact_update_len(ofpacts, ¬e->ofpact);
> }
>
> static void
> parse_fin_timeout(struct ofpbuf *b, char *arg)
> {
> - struct nx_action_fin_timeout *naft;
> + struct ofpact_fin_timeout *oft = ofpact_put_FIN_TIMEOUT(b);
> char *key, *value;
>
> - naft = ofputil_put_NXAST_FIN_TIMEOUT(b);
> while (ofputil_parse_key_value(&arg, &key, &value)) {
> if (!strcmp(key, "idle_timeout")) {
> - naft->fin_idle_timeout = htons(str_to_u16(value, key));
> + oft->fin_idle_timeout = str_to_u16(value, key);
> } else if (!strcmp(key, "hard_timeout")) {
> - naft->fin_hard_timeout = htons(str_to_u16(value, key));
> + oft->fin_hard_timeout = str_to_u16(value, key);
> } else {
> ovs_fatal(0, "invalid key '%s' in 'fin_timeout' argument", key);
> }
> @@ -301,121 +263,142 @@ parse_controller(struct ofpbuf *b, char *arg)
> }
>
> if (reason == OFPR_ACTION && controller_id == 0) {
> - put_output_action(b, OFPP_CONTROLLER)->max_len = htons(max_len);
> + struct ofpact_output *output;
> +
> + output = ofpact_put_OUTPUT(b);
> + output->port = OFPP_CONTROLLER;
> + output->max_len = max_len;
> } else {
> - struct nx_action_controller *nac;
> + struct ofpact_controller *controller;
>
> - nac = ofputil_put_NXAST_CONTROLLER(b);
> - nac->max_len = htons(max_len);
> - nac->reason = reason;
> - nac->controller_id = htons(controller_id);
> + controller = ofpact_put_CONTROLLER(b);
> + controller->max_len = max_len;
> + controller->reason = reason;
> + controller->controller_id = controller_id;
> }
> }
>
> static void
> parse_named_action(enum ofputil_action_code code, const struct flow *flow,
> - struct ofpbuf *b, char *arg)
> + char *arg, struct ofpbuf *ofpacts)
> {
> - struct ofp_action_dl_addr *oada;
> - struct ofp_action_vlan_pcp *oavp;
> - struct ofp_action_vlan_vid *oavv;
> - struct ofp_action_nw_addr *oana;
> - struct ofp_action_tp_port *oata;
> + struct ofpact_tunnel *tunnel;
> + uint16_t vid;
> + ovs_be32 ip;
> + uint8_t pcp;
> + uint8_t tos;
>
> switch (code) {
> case OFPUTIL_ACTION_INVALID:
> NOT_REACHED();
>
> case OFPUTIL_OFPAT10_OUTPUT:
> - parse_output(b, arg);
> + parse_output(arg, ofpacts);
> break;
>
> case OFPUTIL_OFPAT10_SET_VLAN_VID:
> - oavv = ofputil_put_OFPAT10_SET_VLAN_VID(b);
> - oavv->vlan_vid = htons(str_to_u32(arg));
> + vid = str_to_u32(arg);
> + if (vid & ~VLAN_VID_MASK) {
> + ovs_fatal(0, "%s: not a valid VLAN VID", arg);
> + }
> + ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid;
> break;
>
> case OFPUTIL_OFPAT10_SET_VLAN_PCP:
> - oavp = ofputil_put_OFPAT10_SET_VLAN_PCP(b);
> - oavp->vlan_pcp = str_to_u32(arg);
> + pcp = str_to_u32(arg);
> + if (pcp & ~7) {
> + ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
> + }
> + ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp;
> break;
>
> case OFPUTIL_OFPAT10_STRIP_VLAN:
> - ofputil_put_OFPAT10_STRIP_VLAN(b);
> + ofpact_put_STRIP_VLAN(ofpacts);
> break;
>
> case OFPUTIL_OFPAT10_SET_DL_SRC:
> + str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
> + break;
> +
> case OFPUTIL_OFPAT10_SET_DL_DST:
> - oada = ofputil_put_action(code, b);
> - str_to_mac(arg, oada->dl_addr);
> + str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
> break;
>
> case OFPUTIL_OFPAT10_SET_NW_SRC:
> + str_to_ip(arg, &ip);
> + ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
> + break;
> +
> case OFPUTIL_OFPAT10_SET_NW_DST:
> - oana = ofputil_put_action(code, b);
> - str_to_ip(arg, &oana->nw_addr);
> + str_to_ip(arg, &ip);
> + ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
> break;
>
> case OFPUTIL_OFPAT10_SET_NW_TOS:
> - ofputil_put_OFPAT10_SET_NW_TOS(b)->nw_tos = str_to_u32(arg);
> + tos = str_to_u32(arg);
> + if (tos & ~IP_DSCP_MASK) {
> + ovs_fatal(0, "%s: not a valid TOS", arg);
> + }
> + ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos;
> break;
>
> case OFPUTIL_OFPAT10_SET_TP_SRC:
> + ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
> + break;
> +
> case OFPUTIL_OFPAT10_SET_TP_DST:
> - oata = ofputil_put_action(code, b);
> - oata->tp_port = htons(str_to_u32(arg));
> + ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
> break;
>
> case OFPUTIL_OFPAT10_ENQUEUE:
> - parse_enqueue(b, arg);
> + parse_enqueue(arg, ofpacts);
> break;
>
> case OFPUTIL_NXAST_RESUBMIT:
> - parse_resubmit(b, arg);
> + parse_resubmit(arg, ofpacts);
> break;
>
> case OFPUTIL_NXAST_SET_TUNNEL:
> - parse_set_tunnel(b, arg);
> + case OFPUTIL_NXAST_SET_TUNNEL64:
> + tunnel = ofpact_put_SET_TUNNEL(ofpacts);
> + tunnel->ofpact.compat = code;
> + tunnel->tun_id = str_to_u64(arg);
> break;
>
> case OFPUTIL_NXAST_SET_QUEUE:
> - ofputil_put_NXAST_SET_QUEUE(b)->queue_id = htonl(str_to_u32(arg));
> + ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
> break;
>
> case OFPUTIL_NXAST_POP_QUEUE:
> - ofputil_put_NXAST_POP_QUEUE(b);
> + ofpact_put_POP_QUEUE(ofpacts);
> break;
>
> case OFPUTIL_NXAST_REG_MOVE:
> - nxm_parse_reg_move(ofputil_put_NXAST_REG_MOVE(b), arg);
> + nxm_parse_reg_move(ofpact_put_REG_MOVE(ofpacts), arg);
> break;
>
> case OFPUTIL_NXAST_REG_LOAD:
> - nxm_parse_reg_load(ofputil_put_NXAST_REG_LOAD(b), arg);
> + nxm_parse_reg_load(ofpact_put_REG_LOAD(ofpacts), arg);
> break;
>
> case OFPUTIL_NXAST_NOTE:
> - parse_note(b, arg);
> - break;
> -
> - case OFPUTIL_NXAST_SET_TUNNEL64:
> - ofputil_put_NXAST_SET_TUNNEL64(b)->tun_id = htonll(str_to_u64(arg));
> + parse_note(arg, ofpacts);
> break;
>
> case OFPUTIL_NXAST_MULTIPATH:
> - multipath_parse(ofputil_put_NXAST_MULTIPATH(b), arg);
> + multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg);
> break;
>
> case OFPUTIL_NXAST_AUTOPATH:
> - autopath_parse(ofputil_put_NXAST_AUTOPATH(b), arg);
> + autopath_parse(ofpact_put_AUTOPATH(ofpacts), arg);
> break;
>
> case OFPUTIL_NXAST_BUNDLE:
> - bundle_parse(b, arg);
> + bundle_parse(arg, ofpacts);
> break;
>
> case OFPUTIL_NXAST_BUNDLE_LOAD:
> - bundle_parse_load(b, arg);
> + bundle_parse_load(arg, ofpacts);
> break;
>
> case OFPUTIL_NXAST_RESUBMIT_TABLE:
> @@ -423,29 +406,29 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
> NOT_REACHED();
>
> case OFPUTIL_NXAST_LEARN:
> - learn_parse(b, arg, flow);
> + learn_parse(arg, flow, ofpacts);
> break;
>
> case OFPUTIL_NXAST_EXIT:
> - ofputil_put_NXAST_EXIT(b);
> + ofpact_put_EXIT(ofpacts);
> break;
>
> case OFPUTIL_NXAST_DEC_TTL:
> - ofputil_put_NXAST_DEC_TTL(b);
> + ofpact_put_DEC_TTL(ofpacts);
> break;
>
> case OFPUTIL_NXAST_FIN_TIMEOUT:
> - parse_fin_timeout(b, arg);
> + parse_fin_timeout(ofpacts, arg);
> break;
>
> case OFPUTIL_NXAST_CONTROLLER:
> - parse_controller(b, arg);
> + parse_controller(ofpacts, arg);
> break;
> }
> }
>
> static void
> -str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
> +str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
> {
> char *pos, *act, *arg;
> int n_actions;
> @@ -458,10 +441,8 @@ str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
>
> code = ofputil_action_code_from_name(act);
> if (code >= 0) {
> - parse_named_action(code, flow, b, arg);
> + parse_named_action(code, flow, arg, ofpacts);
> } else if (!strcasecmp(act, "drop")) {
> - /* A drop action in OpenFlow occurs by just not setting
> - * an action. */
> if (n_actions) {
> ovs_fatal(0, "Drop actions must not be preceded by other "
> "actions");
> @@ -471,12 +452,13 @@ str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
> }
> break;
> } else if (ofputil_port_from_string(act, &port)) {
> - put_output_action(b, port);
> + ofpact_put_OUTPUT(ofpacts)->port = port;
> } else {
> ovs_fatal(0, "Unknown action: %s", act);
> }
> n_actions++;
> }
> + ofpact_put_END(ofpacts);
> }
>
> struct protocol {
> @@ -694,15 +676,15 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
> fm->new_cookie = htonll(0);
> }
> if (fields & F_ACTIONS) {
> - struct ofpbuf actions;
> + struct ofpbuf ofpacts;
>
> - ofpbuf_init(&actions, sizeof(union ofp_action));
> - str_to_action(&fm->cr.flow, act_str, &actions);
> - fm->actions = ofpbuf_steal_data(&actions);
> - fm->n_actions = actions.size / sizeof(union ofp_action);
> + ofpbuf_init(&ofpacts, 32);
> + str_to_ofpacts(&fm->cr.flow, act_str, &ofpacts);
> + fm->ofpacts_len = ofpacts.size;
> + fm->ofpacts = ofpbuf_steal_data(&ofpacts);
> } else {
> - fm->actions = NULL;
> - fm->n_actions = 0;
> + fm->ofpacts_len = 0;
> + fm->ofpacts = NULL;
> }
>
> free(string);
> @@ -714,10 +696,10 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
> * Prints an error on stderr and aborts the program if 's' syntax is
> * invalid. */
> void
> -parse_ofp_actions(const char *s_, struct ofpbuf *actions)
> +parse_ofpacts(const char *s_, struct ofpbuf *ofpacts)
> {
> char *s = xstrdup(s_);
> - str_to_action(NULL, s, actions);
> + str_to_ofpacts(NULL, s, ofpacts);
> free(s);
> }
>
> diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
> index 3e5e62a..e930388 100644
> --- a/lib/ofp-parse.h
> +++ b/lib/ofp-parse.h
> @@ -40,7 +40,7 @@ void parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
> bool aggregate, const char *string);
>
>
> -void parse_ofp_actions(const char *, struct ofpbuf *actions);
> +void parse_ofpacts(const char *, struct ofpbuf *ofpacts);
>
> char *parse_ofp_exact_flow(struct flow *, const char *);
>
> diff --git a/lib/ofp-print.c b/lib/ofp-print.c
> index 347b69c..6983af7 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -36,6 +36,7 @@
> #include "meta-flow.h"
> #include "netdev.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> @@ -154,278 +155,17 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
> }
>
> static void
> -print_note(struct ds *string, const struct nx_action_note *nan)
> -{
> - size_t len;
> - size_t i;
> -
> - ds_put_cstr(string, "note:");
> - len = ntohs(nan->len) - offsetof(struct nx_action_note, note);
> - for (i = 0; i < len; i++) {
> - if (i) {
> - ds_put_char(string, '.');
> - }
> - ds_put_format(string, "%02"PRIx8, nan->note[i]);
> - }
> -}
> -
> -static void
> -ofp_print_action(struct ds *s, const union ofp_action *a,
> - enum ofputil_action_code code)
> -{
> - const struct ofp_action_enqueue *oae;
> - const struct ofp_action_dl_addr *oada;
> - const struct nx_action_set_tunnel64 *nast64;
> - const struct nx_action_set_tunnel *nast;
> - const struct nx_action_set_queue *nasq;
> - const struct nx_action_resubmit *nar;
> - const struct nx_action_reg_move *move;
> - const struct nx_action_reg_load *load;
> - const struct nx_action_multipath *nam;
> - const struct nx_action_autopath *naa;
> - const struct nx_action_output_reg *naor;
> - const struct nx_action_fin_timeout *naft;
> - const struct nx_action_controller *nac;
> - struct mf_subfield subfield;
> - uint16_t port;
> -
> - switch (code) {
> - case OFPUTIL_ACTION_INVALID:
> - NOT_REACHED();
> -
> - case OFPUTIL_OFPAT10_OUTPUT:
> - port = ntohs(a->output.port);
> - if (port < OFPP_MAX) {
> - ds_put_format(s, "output:%"PRIu16, port);
> - } else {
> - ofputil_format_port(port, s);
> - if (port == OFPP_CONTROLLER) {
> - if (a->output.max_len != htons(0)) {
> - ds_put_format(s, ":%"PRIu16, ntohs(a->output.max_len));
> - } else {
> - ds_put_cstr(s, ":all");
> - }
> - }
> - }
> - break;
> -
> - case OFPUTIL_OFPAT10_ENQUEUE:
> - oae = (const struct ofp_action_enqueue *) a;
> - ds_put_format(s, "enqueue:");
> - ofputil_format_port(ntohs(oae->port), s);
> - ds_put_format(s, "q%"PRIu32, ntohl(oae->queue_id));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_VLAN_VID:
> - ds_put_format(s, "mod_vlan_vid:%"PRIu16,
> - ntohs(a->vlan_vid.vlan_vid));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_VLAN_PCP:
> - ds_put_format(s, "mod_vlan_pcp:%"PRIu8, a->vlan_pcp.vlan_pcp);
> - break;
> -
> - case OFPUTIL_OFPAT10_STRIP_VLAN:
> - ds_put_cstr(s, "strip_vlan");
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_DL_SRC:
> - oada = (const struct ofp_action_dl_addr *) a;
> - ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
> - ETH_ADDR_ARGS(oada->dl_addr));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_DL_DST:
> - oada = (const struct ofp_action_dl_addr *) a;
> - ds_put_format(s, "mod_dl_dst:"ETH_ADDR_FMT,
> - ETH_ADDR_ARGS(oada->dl_addr));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_NW_SRC:
> - ds_put_format(s, "mod_nw_src:"IP_FMT, IP_ARGS(&a->nw_addr.nw_addr));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_NW_DST:
> - ds_put_format(s, "mod_nw_dst:"IP_FMT, IP_ARGS(&a->nw_addr.nw_addr));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_NW_TOS:
> - ds_put_format(s, "mod_nw_tos:%d", a->nw_tos.nw_tos);
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_TP_SRC:
> - ds_put_format(s, "mod_tp_src:%d", ntohs(a->tp_port.tp_port));
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_TP_DST:
> - ds_put_format(s, "mod_tp_dst:%d", ntohs(a->tp_port.tp_port));
> - break;
> -
> - case OFPUTIL_NXAST_RESUBMIT:
> - nar = (struct nx_action_resubmit *)a;
> - ds_put_format(s, "resubmit:");
> - ofputil_format_port(ntohs(nar->in_port), s);
> - break;
> -
> - case OFPUTIL_NXAST_RESUBMIT_TABLE:
> - nar = (struct nx_action_resubmit *)a;
> - ds_put_format(s, "resubmit(");
> - if (nar->in_port != htons(OFPP_IN_PORT)) {
> - ofputil_format_port(ntohs(nar->in_port), s);
> - }
> - ds_put_char(s, ',');
> - if (nar->table != 255) {
> - ds_put_format(s, "%"PRIu8, nar->table);
> - }
> - ds_put_char(s, ')');
> - break;
> -
> - case OFPUTIL_NXAST_SET_TUNNEL:
> - nast = (struct nx_action_set_tunnel *)a;
> - ds_put_format(s, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
> - break;
> -
> - case OFPUTIL_NXAST_SET_QUEUE:
> - nasq = (struct nx_action_set_queue *)a;
> - ds_put_format(s, "set_queue:%u", ntohl(nasq->queue_id));
> - break;
> -
> - case OFPUTIL_NXAST_POP_QUEUE:
> - ds_put_cstr(s, "pop_queue");
> - break;
> -
> - case OFPUTIL_NXAST_NOTE:
> - print_note(s, (const struct nx_action_note *) a);
> - break;
> -
> - case OFPUTIL_NXAST_REG_MOVE:
> - move = (const struct nx_action_reg_move *) a;
> - nxm_format_reg_move(move, s);
> - break;
> -
> - case OFPUTIL_NXAST_REG_LOAD:
> - load = (const struct nx_action_reg_load *) a;
> - nxm_format_reg_load(load, s);
> - break;
> -
> - case OFPUTIL_NXAST_SET_TUNNEL64:
> - nast64 = (const struct nx_action_set_tunnel64 *) a;
> - ds_put_format(s, "set_tunnel64:%#"PRIx64,
> - ntohll(nast64->tun_id));
> - break;
> -
> - case OFPUTIL_NXAST_MULTIPATH:
> - nam = (const struct nx_action_multipath *) a;
> - multipath_format(nam, s);
> - break;
> -
> - case OFPUTIL_NXAST_AUTOPATH:
> - naa = (const struct nx_action_autopath *)a;
> - ds_put_format(s, "autopath(%u,", ntohl(naa->id));
> - nxm_decode(&subfield, naa->dst, naa->ofs_nbits);
> - mf_format_subfield(&subfield, s);
> - ds_put_char(s, ')');
> - break;
> -
> - case OFPUTIL_NXAST_BUNDLE:
> - case OFPUTIL_NXAST_BUNDLE_LOAD:
> - bundle_format((const struct nx_action_bundle *) a, s);
> - break;
> -
> - case OFPUTIL_NXAST_OUTPUT_REG:
> - naor = (const struct nx_action_output_reg *) a;
> - ds_put_cstr(s, "output:");
> - nxm_decode(&subfield, naor->src, naor->ofs_nbits);
> - mf_format_subfield(&subfield, s);
> - break;
> -
> - case OFPUTIL_NXAST_LEARN:
> - learn_format((const struct nx_action_learn *) a, s);
> - break;
> -
> - case OFPUTIL_NXAST_DEC_TTL:
> - ds_put_cstr(s, "dec_ttl");
> - break;
> -
> - case OFPUTIL_NXAST_EXIT:
> - ds_put_cstr(s, "exit");
> - break;
> -
> - case OFPUTIL_NXAST_FIN_TIMEOUT:
> - naft = (const struct nx_action_fin_timeout *) a;
> - ds_put_cstr(s, "fin_timeout(");
> - if (naft->fin_idle_timeout) {
> - ds_put_format(s, "idle_timeout=%"PRIu16",",
> - ntohs(naft->fin_idle_timeout));
> - }
> - if (naft->fin_hard_timeout) {
> - ds_put_format(s, "hard_timeout=%"PRIu16",",
> - ntohs(naft->fin_hard_timeout));
> - }
> - ds_chomp(s, ',');
> - ds_put_char(s, ')');
> - break;
> -
> - case OFPUTIL_NXAST_CONTROLLER:
> - nac = (const struct nx_action_controller *) a;
> - ds_put_cstr(s, "controller(");
> - if (nac->reason != OFPR_ACTION) {
> - ds_put_format(s, "reason=%s,",
> - ofputil_packet_in_reason_to_string(nac->reason));
> - }
> - if (nac->max_len != htons(UINT16_MAX)) {
> - ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
> - }
> - if (nac->controller_id != htons(0)) {
> - ds_put_format(s, "id=%"PRIu16",", ntohs(nac->controller_id));
> - }
> - ds_chomp(s, ',');
> - ds_put_char(s, ')');
> - break;
> -
> - default:
> - break;
> - }
> -}
> -
> -void
> -ofp_print_actions(struct ds *string, const union ofp_action *actions,
> - size_t n_actions)
> -{
> - const union ofp_action *a;
> - size_t left;
> -
> - ds_put_cstr(string, "actions=");
> - if (!n_actions) {
> - ds_put_cstr(string, "drop");
> - }
> -
> - OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) {
> - int code = ofputil_decode_action(a);
> - if (code >= 0) {
> - if (a != actions) {
> - ds_put_cstr(string, ",");
> - }
> - ofp_print_action(string, a, code);
> - } else {
> - ofp_print_error(string, -code);
> - }
> - }
> - if (left > 0) {
> - ds_put_format(string, " ***%zu leftover bytes following actions",
> - left * sizeof *a);
> - }
> -}
> -
> -static void
> ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
> int verbosity)
> {
> struct ofputil_packet_out po;
> + struct ofpbuf ofpacts;
> enum ofperr error;
>
> - error = ofputil_decode_packet_out(&po, opo);
> + ofpbuf_init(&ofpacts, 64);
> + error = ofputil_decode_packet_out(&po, opo, &ofpacts);
> if (error) {
> + ofpbuf_uninit(&ofpacts);
> ofp_print_error(string, error);
> return;
> }
> @@ -434,7 +174,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
> ofputil_format_port(po.in_port, string);
>
> ds_put_char(string, ' ');
> - ofp_print_actions(string, po.actions, po.n_actions);
> + ofpacts_format(po.ofpacts, string);
>
> if (po.buffer_id == UINT32_MAX) {
> ds_put_format(string, " data_len=%zu", po.packet_len);
> @@ -448,6 +188,8 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
> ds_put_format(string, " buffer=0x%08"PRIx32, po.buffer_id);
> }
> ds_put_char(string, '\n');
> +
> + ofpbuf_uninit(&ofpacts);
> }
>
> /* qsort comparison function. */
> @@ -928,11 +670,14 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
> enum ofputil_msg_code code, int verbosity)
> {
> struct ofputil_flow_mod fm;
> + struct ofpbuf ofpacts;
> bool need_priority;
> enum ofperr error;
>
> - error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID);
> + ofpbuf_init(&ofpacts, 64);
> + error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID, &ofpacts);
> if (error) {
> + ofpbuf_uninit(&ofpacts);
> ofp_print_error(s, error);
> return;
> }
> @@ -1027,7 +772,8 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
> }
> }
>
> - ofp_print_actions(s, fm.actions, fm.n_actions);
> + ofpacts_format(fm.ofpacts, s);
> + ofpbuf_uninit(&ofpacts);
> }
>
> static void
> @@ -1229,14 +975,16 @@ ofp_print_flow_stats_request(struct ds *string,
> static void
> ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
> {
> + struct ofpbuf ofpacts;
> struct ofpbuf b;
>
> ofpbuf_use_const(&b, oh, ntohs(oh->length));
> + ofpbuf_init(&ofpacts, 64);
> for (;;) {
> struct ofputil_flow_stats fs;
> int retval;
>
> - retval = ofputil_decode_flow_stats_reply(&fs, &b, true);
> + retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts);
> if (retval) {
> if (retval != EOF) {
> ds_put_cstr(string, " ***parse error***");
> @@ -1269,8 +1017,9 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
> if (string->string[string->length - 1] != ' ') {
> ds_put_char(string, ' ');
> }
> - ofp_print_actions(string, fs.actions, fs.n_actions);
> - }
> + ofpacts_format(fs.ofpacts, string);
> + }
> + ofpbuf_uninit(&ofpacts);
> }
>
> static void
> diff --git a/lib/ofp-print.h b/lib/ofp-print.h
> index ae868a4..49bcfcd 100644
> --- a/lib/ofp-print.h
> +++ b/lib/ofp-print.h
> @@ -25,7 +25,6 @@
> struct ofp_flow_mod;
> struct ofp10_match;
> struct ds;
> -union ofp_action;
>
> #ifdef __cplusplus
> extern "C" {
> @@ -34,7 +33,6 @@ extern "C" {
> void ofp_print(FILE *, const void *, size_t, int verbosity);
> void ofp_print_packet(FILE *stream, const void *data, size_t len);
>
> -void ofp_print_actions(struct ds *, const union ofp_action *, size_t);
> void ofp10_match_print(struct ds *, const struct ofp10_match *, int verbosity);
>
> char *ofp_to_string(const void *, size_t, int verbosity);
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index cebc523..e31a304 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -32,6 +32,7 @@
> #include "multipath.h"
> #include "netdev.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> @@ -1644,11 +1645,17 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
> * flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
> * code.
> *
> - * Does not validate the flow_mod actions. */
> + * Uses 'ofpacts' to store the abstract OFPACT_* version of 'oh''s actions.
> + * The caller must initialize 'ofpacts' and retains ownership of it.
> + * 'fm->ofpacts' will point into the 'ofpacts' buffer.
> + *
> + * Does not validate the flow_mod actions. The caller should do that, with
> + * ofpacts_check(). */
> enum ofperr
> ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
> const struct ofp_header *oh,
> - enum ofputil_protocol protocol)
> + enum ofputil_protocol protocol,
> + struct ofpbuf *ofpacts)
> {
> const struct ofputil_msg_type *type;
> uint16_t command;
> @@ -1663,12 +1670,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
> uint16_t priority;
> enum ofperr error;
>
> - /* Dissect the message. */
> + /* Get the ofp_flow_mod. */
> ofm = ofpbuf_pull(&b, sizeof *ofm);
> - error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions);
> - if (error) {
> - return error;
> - }
>
> /* Set priority based on original wildcards. Normally we'd allow
> * ofputil_cls_rule_from_match() to do this for us, but
> @@ -1683,6 +1686,12 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
> ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
> ofputil_normalize_rule(&fm->cr);
>
> + /* Now get the actions. */
> + error = ofpacts_pull_openflow(&b, b.size, ofpacts);
> + if (error) {
> + return error;
> + }
> +
> /* Translate the message. */
> command = ntohs(ofm->command);
> fm->cookie = htonll(0);
> @@ -1705,7 +1714,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
> if (error) {
> return error;
> }
> - error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions);
> + error = ofpacts_pull_openflow(&b, b.size, ofpacts);
> if (error) {
> return error;
> }
> @@ -1727,6 +1736,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
> NOT_REACHED();
> }
>
> + fm->ofpacts = ofpacts->data;
> + fm->ofpacts_len = ofpacts->size;
> if (protocol & OFPUTIL_P_TID) {
> fm->command = command & 0xff;
> fm->table_id = command >> 8;
> @@ -1744,7 +1755,6 @@ struct ofpbuf *
> ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
> enum ofputil_protocol protocol)
> {
> - size_t actions_len = fm->n_actions * sizeof *fm->actions;
> struct ofp_flow_mod *ofm;
> struct nx_flow_mod *nfm;
> struct ofpbuf *msg;
> @@ -1758,7 +1768,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
> switch (protocol) {
> case OFPUTIL_P_OF10:
> case OFPUTIL_P_OF10_TID:
> - msg = ofpbuf_new(sizeof *ofm + actions_len);
> + msg = ofpbuf_new(sizeof *ofm + fm->ofpacts_len);
> ofm = put_openflow(sizeof *ofm, OFPT10_FLOW_MOD, msg);
> ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match);
> ofm->cookie = fm->new_cookie;
> @@ -1773,7 +1783,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
>
> case OFPUTIL_P_NXM:
> case OFPUTIL_P_NXM_TID:
> - msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + actions_len);
> + msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + fm->ofpacts_len);
> put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
> nfm = msg->data;
> nfm->command = htons(command);
> @@ -1794,7 +1804,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
> NOT_REACHED();
> }
>
> - ofpbuf_put(msg, fm->actions, actions_len);
> + if (fm->ofpacts) {
> + ofpacts_to_openflow(fm->ofpacts, msg);
> + }
> update_openflow_length(msg);
> return msg;
> }
> @@ -1988,12 +2000,17 @@ ofputil_flow_stats_request_usable_protocols(
> * 'flow_age_extension' as true so that the contents of 'msg' determine the
> * 'idle_age' and 'hard_age' members in 'fs'.
> *
> + * Uses 'ofpacts' to store the abstract OFPACT_* version of the flow stats
> + * reply's actions. The caller must initialize 'ofpacts' and retains ownership
> + * of it. 'fs->ofpacts' will point into the 'ofpacts' buffer.
> + *
> * Returns 0 if successful, EOF if no replies were left in this 'msg',
> * otherwise a positive errno value. */
> int
> ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
> struct ofpbuf *msg,
> - bool flow_age_extension)
> + bool flow_age_extension,
> + struct ofpbuf *ofpacts)
> {
> const struct ofputil_msg_type *type;
> int code;
> @@ -2031,8 +2048,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
> return EINVAL;
> }
>
> - if (ofputil_pull_actions(msg, length - sizeof *ofs,
> - &fs->actions, &fs->n_actions)) {
> + if (ofpacts_pull_openflow(msg, length - sizeof *ofs, ofpacts)) {
> return EINVAL;
> }
>
> @@ -2050,7 +2066,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
> fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
> } else if (code == OFPUTIL_NXST_FLOW_REPLY) {
> const struct nx_flow_stats *nfs;
> - size_t match_len, length;
> + size_t match_len, actions_len, length;
>
> nfs = ofpbuf_try_pull(msg, sizeof *nfs);
> if (!nfs) {
> @@ -2071,9 +2087,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
> return EINVAL;
> }
>
> - if (ofputil_pull_actions(msg,
> - length - sizeof *nfs - ROUND_UP(match_len, 8),
> - &fs->actions, &fs->n_actions)) {
> + actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
> + if (ofpacts_pull_openflow(msg, actions_len, ofpacts)) {
> return EINVAL;
> }
>
> @@ -2099,6 +2114,9 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
> NOT_REACHED();
> }
>
> + fs->ofpacts = ofpacts->data;
> + fs->ofpacts_len = ofpacts->size;
> +
> return 0;
> }
>
> @@ -2119,16 +2137,14 @@ void
> ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
> struct list *replies)
> {
> - size_t act_len = fs->n_actions * sizeof *fs->actions;
> - const struct ofp_stats_msg *osm;
> + struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
> + const struct ofp_stats_msg *osm = reply->data;
> + size_t start_ofs = reply->size;
>
> - osm = ofpbuf_from_list(list_back(replies))->data;
> if (osm->type == htons(OFPST_FLOW)) {
> - size_t len = offsetof(struct ofp_flow_stats, actions) + act_len;
> struct ofp_flow_stats *ofs;
>
> - ofs = ofputil_append_stats_reply(len, replies);
> - ofs->length = htons(len);
> + ofs = ofpbuf_put_uninit(reply, sizeof *ofs);
> ofs->table_id = fs->table_id;
> ofs->pad = 0;
> ofputil_cls_rule_to_ofp10_match(&fs->rule, &ofs->match);
> @@ -2143,17 +2159,14 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
> htonll(unknown_to_zero(fs->packet_count)));
> put_32aligned_be64(&ofs->byte_count,
> htonll(unknown_to_zero(fs->byte_count)));
> - memcpy(ofs->actions, fs->actions, act_len);
> + ofpacts_to_openflow(fs->ofpacts, reply);
> +
> + ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
> + ofs->length = htons(reply->size - start_ofs);
> } else if (osm->type == htons(OFPST_VENDOR)) {
> struct nx_flow_stats *nfs;
> - struct ofpbuf *msg;
> - size_t start_len;
>
> - msg = ofputil_reserve_stats_reply(
> - sizeof *nfs + NXM_MAX_LEN + act_len, replies);
> - start_len = msg->size;
> -
> - nfs = ofpbuf_put_uninit(msg, sizeof *nfs);
> + nfs = ofpbuf_put_uninit(reply, sizeof *nfs);
> nfs->table_id = fs->table_id;
> nfs->pad = 0;
> nfs->duration_sec = htonl(fs->duration_sec);
> @@ -2167,15 +2180,19 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
> nfs->hard_age = htons(fs->hard_age < 0 ? 0
> : fs->hard_age < UINT16_MAX ? fs->hard_age + 1
> : UINT16_MAX);
> - nfs->match_len = htons(nx_put_match(msg, false, &fs->rule, 0, 0));
> + nfs->match_len = htons(nx_put_match(reply, false, &fs->rule, 0, 0));
> nfs->cookie = fs->cookie;
> nfs->packet_count = htonll(fs->packet_count);
> nfs->byte_count = htonll(fs->byte_count);
> - ofpbuf_put(msg, fs->actions, act_len);
> - nfs->length = htons(msg->size - start_len);
> + ofpacts_to_openflow(fs->ofpacts, reply);
> +
> + nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
> + nfs->length = htons(reply->size - start_ofs);
> } else {
> NOT_REACHED();
> }
> +
> + ofputil_postappend_stats_reply(start_ofs, replies);
> }
>
> /* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
> @@ -2501,9 +2518,18 @@ ofputil_packet_in_reason_from_string(const char *s,
> return false;
> }
>
> +/* Converts an OFPT_PACKET_OUT in 'opo' into an abstract ofputil_packet_out in
> + * 'po'.
> + *
> + * Uses 'ofpacts' to store the abstract OFPACT_* version of the packet out
> + * message's actions. The caller must initialize 'ofpacts' and retains
> + * ownership of it. 'po->ofpacts' will point into the 'ofpacts' buffer.
> + *
> + * Returns 0 if successful, otherwise an OFPERR_* value. */
> enum ofperr
> ofputil_decode_packet_out(struct ofputil_packet_out *po,
> - const struct ofp_packet_out *opo)
> + const struct ofp_packet_out *opo,
> + struct ofpbuf *ofpacts)
> {
> enum ofperr error;
> struct ofpbuf b;
> @@ -2520,11 +2546,12 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
> ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
> ofpbuf_pull(&b, sizeof *opo);
>
> - error = ofputil_pull_actions(&b, ntohs(opo->actions_len),
> - &po->actions, &po->n_actions);
> + error = ofpacts_pull_openflow(&b, ntohs(opo->actions_len), ofpacts);
> if (error) {
> return error;
> }
> + po->ofpacts = ofpacts->data;
> + po->ofpacts_len = ofpacts->size;
>
> if (po->buffer_id == UINT32_MAX) {
> po->packet = b.data;
> @@ -3070,25 +3097,27 @@ struct ofpbuf *
> ofputil_encode_packet_out(const struct ofputil_packet_out *po)
> {
> struct ofp_packet_out *opo;
> - size_t actions_len;
> struct ofpbuf *msg;
> size_t size;
>
> - actions_len = po->n_actions * sizeof *po->actions;
> - size = sizeof *opo + actions_len;
> + size = sizeof *opo + po->ofpacts_len;
> if (po->buffer_id == UINT32_MAX) {
> size += po->packet_len;
> }
>
> msg = ofpbuf_new(size);
> - opo = put_openflow(sizeof *opo, OFPT10_PACKET_OUT, msg);
> + put_openflow(sizeof *opo, OFPT10_PACKET_OUT, msg);
> + ofpacts_to_openflow(po->ofpacts, msg);
> +
> + opo = msg->data;
> opo->buffer_id = htonl(po->buffer_id);
> opo->in_port = htons(po->in_port);
> - opo->actions_len = htons(actions_len);
> - ofpbuf_put(msg, po->actions, actions_len);
> + opo->actions_len = htons(msg->size - sizeof *opo);
> +
> if (po->buffer_id == UINT32_MAX) {
> ofpbuf_put(msg, po->packet, po->packet_len);
> }
> +
> update_openflow_length(msg);
>
> return msg;
> @@ -3362,6 +3391,20 @@ ofputil_append_stats_reply(size_t len, struct list *replies)
> return ofpbuf_put_uninit(ofputil_reserve_stats_reply(len, replies), len);
> }
>
> +void
> +ofputil_postappend_stats_reply(size_t start_ofs, struct list *replies)
> +{
> + struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
> +
> + assert(start_ofs <= UINT16_MAX);
> + if (msg->size > UINT16_MAX) {
> + size_t len = msg->size - start_ofs;
> + memcpy(ofputil_append_stats_reply(len, replies),
> + (const uint8_t *) msg->data + start_ofs, len);
> + msg->size = start_ofs;
> + }
> +}
> +
> /* Returns the first byte past the ofp_stats_msg header in 'oh'. */
> const void *
> ofputil_stats_body(const struct ofp_header *oh)
> @@ -3661,280 +3704,6 @@ size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b)
> return b->size / ofputil_get_phy_port_size(ofp_version);
> }
>
> -static enum ofperr
> -check_resubmit_table(const struct nx_action_resubmit *nar)
> -{
> - if (nar->pad[0] || nar->pad[1] || nar->pad[2]) {
> - return OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> - return 0;
> -}
> -
> -static enum ofperr
> -check_output_reg(const struct nx_action_output_reg *naor,
> - const struct flow *flow)
> -{
> - struct mf_subfield src;
> - size_t i;
> -
> - for (i = 0; i < sizeof naor->zero; i++) {
> - if (naor->zero[i]) {
> - return OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> - }
> -
> - nxm_decode(&src, naor->src, naor->ofs_nbits);
> - return mf_check_src(&src, flow);
> -}
> -
> -enum ofperr
> -validate_actions(const union ofp_action *actions, size_t n_actions,
> - const struct flow *flow, int max_ports)
> -{
> - const union ofp_action *a;
> - size_t left;
> -
> - OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) {
> - enum ofperr error;
> - uint16_t port;
> - int code;
> -
> - code = ofputil_decode_action(a);
> - if (code < 0) {
> - error = -code;
> - VLOG_WARN_RL(&bad_ofmsg_rl,
> - "action decoding error at offset %td (%s)",
> - (a - actions) * sizeof *a, ofperr_get_name(error));
> -
> - return error;
> - }
> -
> - error = 0;
> - switch ((enum ofputil_action_code) code) {
> - case OFPUTIL_ACTION_INVALID:
> - NOT_REACHED();
> -
> - case OFPUTIL_OFPAT10_OUTPUT:
> - error = ofputil_check_output_port(ntohs(a->output.port),
> - max_ports);
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_VLAN_VID:
> - if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
> - error = OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_VLAN_PCP:
> - if (a->vlan_pcp.vlan_pcp & ~7) {
> - error = OFPERR_OFPBAC_BAD_ARGUMENT;
> - }
> - break;
> -
> - case OFPUTIL_OFPAT10_ENQUEUE:
> - port = ntohs(((const struct ofp_action_enqueue *) a)->port);
> - if (port >= max_ports && port != OFPP_IN_PORT
> - && port != OFPP_LOCAL) {
> - error = OFPERR_OFPBAC_BAD_OUT_PORT;
> - }
> - break;
> -
> - case OFPUTIL_NXAST_REG_MOVE:
> - error = nxm_check_reg_move((const struct nx_action_reg_move *) a,
> - flow);
> - break;
> -
> - case OFPUTIL_NXAST_REG_LOAD:
> - error = nxm_check_reg_load((const struct nx_action_reg_load *) a,
> - flow);
> - break;
> -
> - case OFPUTIL_NXAST_MULTIPATH:
> - error = multipath_check((const struct nx_action_multipath *) a,
> - flow);
> - break;
> -
> - case OFPUTIL_NXAST_AUTOPATH:
> - error = autopath_check((const struct nx_action_autopath *) a,
> - flow);
> - break;
> -
> - case OFPUTIL_NXAST_BUNDLE:
> - case OFPUTIL_NXAST_BUNDLE_LOAD:
> - error = bundle_check((const struct nx_action_bundle *) a,
> - max_ports, flow);
> - break;
> -
> - case OFPUTIL_NXAST_OUTPUT_REG:
> - error = check_output_reg((const struct nx_action_output_reg *) a,
> - flow);
> - break;
> -
> - case OFPUTIL_NXAST_RESUBMIT_TABLE:
> - error = check_resubmit_table(
> - (const struct nx_action_resubmit *) a);
> - break;
> -
> - case OFPUTIL_NXAST_LEARN:
> - error = learn_check((const struct nx_action_learn *) a, flow);
> - break;
> -
> - case OFPUTIL_NXAST_CONTROLLER:
> - if (((const struct nx_action_controller *) a)->zero) {
> - error = OFPERR_NXBAC_MUST_BE_ZERO;
> - }
> - break;
> -
> - case OFPUTIL_OFPAT10_STRIP_VLAN:
> - case OFPUTIL_OFPAT10_SET_NW_SRC:
> - case OFPUTIL_OFPAT10_SET_NW_DST:
> - case OFPUTIL_OFPAT10_SET_NW_TOS:
> - case OFPUTIL_OFPAT10_SET_TP_SRC:
> - case OFPUTIL_OFPAT10_SET_TP_DST:
> - case OFPUTIL_OFPAT10_SET_DL_SRC:
> - case OFPUTIL_OFPAT10_SET_DL_DST:
> - case OFPUTIL_NXAST_RESUBMIT:
> - case OFPUTIL_NXAST_SET_TUNNEL:
> - case OFPUTIL_NXAST_SET_QUEUE:
> - case OFPUTIL_NXAST_POP_QUEUE:
> - case OFPUTIL_NXAST_NOTE:
> - case OFPUTIL_NXAST_SET_TUNNEL64:
> - case OFPUTIL_NXAST_EXIT:
> - case OFPUTIL_NXAST_DEC_TTL:
> - case OFPUTIL_NXAST_FIN_TIMEOUT:
> - break;
> - }
> -
> - if (error) {
> - VLOG_WARN_RL(&bad_ofmsg_rl, "bad action at offset %td (%s)",
> - (a - actions) * sizeof *a, ofperr_get_name(error));
> - return error;
> - }
> - }
> - if (left) {
> - VLOG_WARN_RL(&bad_ofmsg_rl, "bad action format at offset %zu",
> - (n_actions - left) * sizeof *a);
> - return OFPERR_OFPBAC_BAD_LEN;
> - }
> - return 0;
> -}
> -
> -struct ofputil_action {
> - int code;
> - unsigned int min_len;
> - unsigned int max_len;
> -};
> -
> -static const struct ofputil_action action_bad_type
> - = { -OFPERR_OFPBAC_BAD_TYPE, 0, UINT_MAX };
> -static const struct ofputil_action action_bad_len
> - = { -OFPERR_OFPBAC_BAD_LEN, 0, UINT_MAX };
> -static const struct ofputil_action action_bad_vendor
> - = { -OFPERR_OFPBAC_BAD_VENDOR, 0, UINT_MAX };
> -
> -static const struct ofputil_action *
> -ofputil_decode_ofpat_action(const union ofp_action *a)
> -{
> - enum ofp10_action_type type = ntohs(a->type);
> -
> - switch (type) {
> -#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
> - case ENUM: { \
> - static const struct ofputil_action action = { \
> - OFPUTIL_##ENUM, \
> - sizeof(struct STRUCT), \
> - sizeof(struct STRUCT) \
> - }; \
> - return &action; \
> - }
> -#include "ofp-util.def"
> -
> - case OFPAT10_VENDOR:
> - default:
> - return &action_bad_type;
> - }
> -}
> -
> -static const struct ofputil_action *
> -ofputil_decode_nxast_action(const union ofp_action *a)
> -{
> - const struct nx_action_header *nah = (const struct nx_action_header *) a;
> - enum nx_action_subtype subtype = ntohs(nah->subtype);
> -
> - switch (subtype) {
> -#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
> - case ENUM: { \
> - static const struct ofputil_action action = { \
> - OFPUTIL_##ENUM, \
> - sizeof(struct STRUCT), \
> - EXTENSIBLE ? UINT_MAX : sizeof(struct STRUCT) \
> - }; \
> - return &action; \
> - }
> -#include "ofp-util.def"
> -
> - case NXAST_SNAT__OBSOLETE:
> - case NXAST_DROP_SPOOFED_ARP__OBSOLETE:
> - default:
> - return &action_bad_type;
> - }
> -}
> -
> -/* Parses 'a' to determine its type. Returns a nonnegative OFPUTIL_OFPAT10_* or
> - * OFPUTIL_NXAST_* constant if successful, otherwise a negative OFPERR_* error
> - * code.
> - *
> - * The caller must have already verified that 'a''s length is correct (that is,
> - * a->header.len is nonzero and a multiple of sizeof(union ofp_action) and no
> - * longer than the amount of space allocated to 'a').
> - *
> - * This function verifies that 'a''s length is correct for the type of action
> - * that it represents. */
> -int
> -ofputil_decode_action(const union ofp_action *a)
> -{
> - const struct ofputil_action *action;
> - uint16_t len = ntohs(a->header.len);
> -
> - if (a->type != htons(OFPAT10_VENDOR)) {
> - action = ofputil_decode_ofpat_action(a);
> - } else {
> - switch (ntohl(a->vendor.vendor)) {
> - case NX_VENDOR_ID:
> - if (len < sizeof(struct nx_action_header)) {
> - return -OFPERR_OFPBAC_BAD_LEN;
> - }
> - action = ofputil_decode_nxast_action(a);
> - break;
> - default:
> - action = &action_bad_vendor;
> - break;
> - }
> - }
> -
> - return (len >= action->min_len && len <= action->max_len
> - ? action->code
> - : -OFPERR_OFPBAC_BAD_LEN);
> -}
> -
> -/* Parses 'a' and returns its type as an OFPUTIL_OFPAT10_* or OFPUTIL_NXAST_*
> - * constant. The caller must have already validated that 'a' is a valid action
> - * understood by Open vSwitch (e.g. by a previous successful call to
> - * ofputil_decode_action()). */
> -enum ofputil_action_code
> -ofputil_decode_action_unsafe(const union ofp_action *a)
> -{
> - const struct ofputil_action *action;
> -
> - if (a->type != htons(OFPAT10_VENDOR)) {
> - action = ofputil_decode_ofpat_action(a);
> - } else {
> - action = ofputil_decode_nxast_action(a);
> - }
> -
> - return action->code;
> -}
> -
> /* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if
> * 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1 if
> * 'name' is not the name of any action.
> @@ -4017,22 +3786,6 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
> }
> #include "ofp-util.def"
>
> -/* Returns true if 'action' outputs to 'port', false otherwise. */
> -bool
> -action_outputs_to_port(const union ofp_action *action, ovs_be16 port)
> -{
> - switch (ofputil_decode_action(action)) {
> - case OFPUTIL_OFPAT10_OUTPUT:
> - return action->output.port == port;
> - case OFPUTIL_OFPAT10_ENQUEUE:
> - return ((const struct ofp_action_enqueue *) action)->port == port;
> - case OFPUTIL_NXAST_CONTROLLER:
> - return port == htons(OFPP_CONTROLLER);
> - default:
> - return false;
> - }
> -}
> -
> /* "Normalizes" the wildcards in 'rule'. That means:
> *
> * 1. If the type of level N is known, then only the valid fields for that
> @@ -4140,57 +3893,6 @@ ofputil_normalize_rule(struct cls_rule *rule)
> }
> }
>
> -/* Attempts to pull 'actions_len' bytes from the front of 'b'. Returns 0 if
> - * successful, otherwise an OpenFlow error.
> - *
> - * If successful, the first action is stored in '*actionsp' and the number of
> - * "union ofp_action" size elements into '*n_actionsp'. Otherwise NULL and 0
> - * are stored, respectively.
> - *
> - * This function does not check that the actions are valid (the caller should
> - * do so, with validate_actions()). The caller is also responsible for making
> - * sure that 'b->data' is initially aligned appropriately for "union
> - * ofp_action". */
> -enum ofperr
> -ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len,
> - union ofp_action **actionsp, size_t *n_actionsp)
> -{
> - if (actions_len % OFP_ACTION_ALIGN != 0) {
> - VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message actions length %u "
> - "is not a multiple of %d", actions_len, OFP_ACTION_ALIGN);
> - goto error;
> - }
> -
> - *actionsp = ofpbuf_try_pull(b, actions_len);
> - if (*actionsp == NULL) {
> - VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message actions length %u "
> - "exceeds remaining message length (%zu)",
> - actions_len, b->size);
> - goto error;
> - }
> -
> - *n_actionsp = actions_len / OFP_ACTION_ALIGN;
> - return 0;
> -
> -error:
> - *actionsp = NULL;
> - *n_actionsp = 0;
> - return OFPERR_OFPBRC_BAD_LEN;
> -}
> -
> -bool
> -ofputil_actions_equal(const union ofp_action *a, size_t n_a,
> - const union ofp_action *b, size_t n_b)
> -{
> - return n_a == n_b && (!n_a || !memcmp(a, b, n_a * sizeof *a));
> -}
> -
> -union ofp_action *
> -ofputil_actions_clone(const union ofp_action *actions, size_t n)
> -{
> - return n ? xmemdup(actions, n * sizeof *actions) : NULL;
> -}
> -
> /* Parses a key or a key-value pair from '*stringp'.
> *
> * On success: Stores the key into '*keyp'. Stores the value, if present, into
> diff --git a/lib/ofp-util.h b/lib/ofp-util.h
> index 3f9e440..f703c8a 100644
> --- a/lib/ofp-util.h
> +++ b/lib/ofp-util.h
> @@ -22,6 +22,7 @@
> #include <stddef.h>
> #include <stdint.h>
> #include "classifier.h"
> +#include "compiler.h"
> #include "flow.h"
> #include "netdev.h"
> #include "openflow/nicira-ext.h"
> @@ -236,13 +237,14 @@ struct ofputil_flow_mod {
> uint32_t buffer_id;
> uint16_t out_port;
> uint16_t flags;
> - union ofp_action *actions;
> - size_t n_actions;
> + struct ofpact *ofpacts; /* Series of "struct ofpact"s. */
> + size_t ofpacts_len; /* Length of ofpacts, in bytes. */
> };
>
> enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *,
> const struct ofp_header *,
> - enum ofputil_protocol);
> + enum ofputil_protocol,
> + struct ofpbuf *ofpacts);
> struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *,
> enum ofputil_protocol);
>
> @@ -279,13 +281,14 @@ struct ofputil_flow_stats {
> int hard_age; /* Seconds since last change, -1 if unknown. */
> uint64_t packet_count; /* Packet count, UINT64_MAX if unknown. */
> uint64_t byte_count; /* Byte count, UINT64_MAX if unknown. */
> - union ofp_action *actions;
> - size_t n_actions;
> + struct ofpact *ofpacts;
> + size_t ofpacts_len;
> };
>
> int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *,
> struct ofpbuf *msg,
> - bool flow_age_extension);
> + bool flow_age_extension,
> + struct ofpbuf *ofpacts);
> void ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *,
> struct list *replies);
>
> @@ -352,12 +355,13 @@ struct ofputil_packet_out {
> size_t packet_len; /* Length of packet data in bytes. */
> uint32_t buffer_id; /* Buffer id or UINT32_MAX if no buffer. */
> uint16_t in_port; /* Packet's input port. */
> - union ofp_action *actions; /* Actions. */
> - size_t n_actions; /* Number of elements in 'actions' array. */
> + struct ofpact *ofpacts; /* Actions. */
> + size_t ofpacts_len; /* Size of ofpacts in bytes. */
> };
>
> enum ofperr ofputil_decode_packet_out(struct ofputil_packet_out *,
> - const struct ofp_packet_out *);
> + const struct ofp_packet_out *,
> + struct ofpbuf *ofpacts);
> struct ofpbuf *ofputil_encode_packet_out(const struct ofputil_packet_out *);
>
> enum ofputil_port_config {
> @@ -531,6 +535,7 @@ void ofputil_start_stats_reply(const struct ofp_stats_msg *request,
> struct list *);
> struct ofpbuf *ofputil_reserve_stats_reply(size_t len, struct list *);
> void *ofputil_append_stats_reply(size_t len, struct list *);
> +void ofputil_postappend_stats_reply(size_t start_ofs, struct list *);
>
> void ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
> const struct ofputil_phy_port *pp,
> @@ -597,7 +602,7 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
> *
> * (The above list helps developers who want to "grep" for these definitions.)
> */
> -enum ofputil_action_code {
> +enum OVS_PACKED_ENUM ofputil_action_code {
> OFPUTIL_ACTION_INVALID,
> #define OFPAT10_ACTION(ENUM, STRUCT, NAME) OFPUTIL_##ENUM,
> #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
> @@ -612,10 +617,6 @@ enum {
> #include "ofp-util.def"
> };
>
> -int ofputil_decode_action(const union ofp_action *);
> -enum ofputil_action_code ofputil_decode_action_unsafe(
> - const union ofp_action *);
> -
> int ofputil_action_code_from_name(const char *);
>
> void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
> @@ -644,38 +645,6 @@ void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
>
> #define OFP_ACTION_ALIGN 8 /* Alignment of ofp_actions. */
>
> -static inline union ofp_action *
> -ofputil_action_next(const union ofp_action *a)
> -{
> - return ((union ofp_action *) (void *)
> - ((uint8_t *) a + ntohs(a->header.len)));
> -}
> -
> -static inline bool
> -ofputil_action_is_valid(const union ofp_action *a, size_t n_actions)
> -{
> - uint16_t len = ntohs(a->header.len);
> - return (!(len % OFP_ACTION_ALIGN)
> - && len >= sizeof *a
> - && len / sizeof *a <= n_actions);
> -}
> -
> -/* This macro is careful to check for actions with bad lengths. */
> -#define OFPUTIL_ACTION_FOR_EACH(ITER, LEFT, ACTIONS, N_ACTIONS) \
> - for ((ITER) = (ACTIONS), (LEFT) = (N_ACTIONS); \
> - (LEFT) > 0 && ofputil_action_is_valid(ITER, LEFT); \
> - ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
> - (ITER) = ofputil_action_next(ITER)))
> -
> -/* This macro does not check for actions with bad lengths. It should only be
> - * used with actions from trusted sources or with actions that have already
> - * been validated (e.g. with OFPUTIL_ACTION_FOR_EACH). */
> -#define OFPUTIL_ACTION_FOR_EACH_UNSAFE(ITER, LEFT, ACTIONS, N_ACTIONS) \
> - for ((ITER) = (ACTIONS), (LEFT) = (N_ACTIONS); \
> - (LEFT) > 0; \
> - ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
> - (ITER) = ofputil_action_next(ITER)))
> -
> enum ofperr validate_actions(const union ofp_action *, size_t n_actions,
> const struct flow *, int max_ports);
> bool action_outputs_to_port(const union ofp_action *, ovs_be16 port);
> diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
> index 8cdaa1f..93e5a71 100644
> --- a/ofproto/connmgr.c
> +++ b/ofproto/connmgr.c
> @@ -25,6 +25,7 @@
> #include "fail-open.h"
> #include "in-band.h"
> #include "odp-util.h"
> +#include "ofp-actions.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> #include "ofproto-provider.h"
> @@ -1573,15 +1574,17 @@ connmgr_flushed(struct connmgr *mgr)
> * traffic until a controller has been defined and it tells us to do so. */
> if (!connmgr_has_controllers(mgr)
> && mgr->fail_mode == OFPROTO_FAIL_STANDALONE) {
> - union ofp_action action;
> + struct ofpbuf ofpacts;
> struct cls_rule rule;
>
> - memset(&action, 0, sizeof action);
> - action.type = htons(OFPAT10_OUTPUT);
> - action.output.len = htons(sizeof action);
> - action.output.port = htons(OFPP_NORMAL);
> + ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE + OFPACT_END_SIZE);
> + ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL;
> + ofpact_put_END(&ofpacts);
> +
> cls_rule_init_catchall(&rule, 0);
> - ofproto_add_flow(mgr->ofproto, &rule, &action, 1);
> + ofproto_add_flow(mgr->ofproto, &rule, ofpacts.data, ofpacts.size);
> +
> + ofpbuf_uninit(&ofpacts);
> }
> }
>
> diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c
> index 912dc4e..3baa7b4 100644
> --- a/ofproto/fail-open.c
> +++ b/ofproto/fail-open.c
> @@ -23,6 +23,7 @@
> #include "flow.h"
> #include "mac-learning.h"
> #include "odp-util.h"
> +#include "ofp-actions.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> #include "ofproto.h"
> @@ -214,18 +215,19 @@ fail_open_flushed(struct fail_open *fo)
> int disconn_secs = connmgr_failure_duration(fo->connmgr);
> bool open = disconn_secs >= trigger_duration(fo);
> if (open) {
> - union ofp_action action;
> + struct ofpbuf ofpacts;
> struct cls_rule rule;
>
> /* Set up a flow that matches every packet and directs them to
> * OFPP_NORMAL. */
> - memset(&action, 0, sizeof action);
> - action.type = htons(OFPAT10_OUTPUT);
> - action.output.len = htons(sizeof action);
> - action.output.port = htons(OFPP_NORMAL);
> + ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE + OFPACT_END_SIZE);
> + ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL;
> + ofpact_put_END(&ofpacts);
>
> cls_rule_init_catchall(&rule, FAIL_OPEN_PRIORITY);
> - ofproto_add_flow(fo->ofproto, &rule, &action, 1);
> + ofproto_add_flow(fo->ofproto, &rule, ofpacts.data, ofpacts.size);
> +
> + ofpbuf_uninit(&ofpacts);
> }
> }
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index f51182a..8013598 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -42,6 +42,7 @@
> #include "odp-util.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> +#include "ofp-actions.h"
> #include "ofp-parse.h"
> #include "ofp-print.h"
> #include "ofproto-dpif-governor.h"
> @@ -280,12 +281,10 @@ static void action_xlate_ctx_init(struct action_xlate_ctx *,
> struct ofproto_dpif *, const struct flow *,
> ovs_be16 initial_tci, struct rule_dpif *,
> uint8_t tcp_flags, const struct ofpbuf *);
> -static void xlate_actions(struct action_xlate_ctx *,
> - const union ofp_action *in, size_t n_in,
> +static void xlate_actions(struct action_xlate_ctx *, const struct ofpact *in,
> struct ofpbuf *odp_actions);
> static void xlate_actions_for_side_effects(struct action_xlate_ctx *,
> - const union ofp_action *in,
> - size_t n_in);
> + const struct ofpact *in);
>
> static size_t put_userspace_action(const struct ofproto_dpif *,
> struct ofpbuf *odp_actions,
> @@ -804,7 +803,7 @@ construct(struct ofproto *ofproto_)
>
> static int
> add_internal_flow(struct ofproto_dpif *ofproto, int id,
> - const struct ofpbuf *actions, struct rule_dpif **rulep)
> + const struct ofpbuf *ofpacts, struct rule_dpif **rulep)
> {
> struct ofputil_flow_mod fm;
> int error;
> @@ -821,8 +820,8 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
> fm.buffer_id = 0;
> fm.out_port = 0;
> fm.flags = 0;
> - fm.actions = actions->data;
> - fm.n_actions = actions->size / sizeof(union ofp_action);
> + fm.ofpacts = ofpacts->data;
> + fm.ofpacts_len = ofpacts->size;
>
> error = ofproto_flow_mod(&ofproto->up, &fm);
> if (error) {
> @@ -840,26 +839,29 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
> static int
> add_internal_flows(struct ofproto_dpif *ofproto)
> {
> - struct nx_action_controller *nac;
> - uint64_t actions_stub[128 / 8];
> - struct ofpbuf actions;
> + struct ofpact_controller *controller;
> + uint64_t ofpacts_stub[128 / 8];
> + struct ofpbuf ofpacts;
> int error;
> int id;
>
> - ofpbuf_use_stack(&actions, actions_stub, sizeof actions_stub);
> + ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
> id = 1;
>
> - nac = ofputil_put_NXAST_CONTROLLER(&actions);
> - nac->max_len = htons(UINT16_MAX);
> - nac->controller_id = htons(0);
> - nac->reason = OFPR_NO_MATCH;
> - error = add_internal_flow(ofproto, id++, &actions, &ofproto->miss_rule);
> + controller = ofpact_put_CONTROLLER(&ofpacts);
> + controller->max_len = UINT16_MAX;
> + controller->controller_id = 0;
> + controller->reason = OFPR_NO_MATCH;
> + ofpact_put_END(&ofpacts);
> +
> + error = add_internal_flow(ofproto, id++, &ofpacts, &ofproto->miss_rule);
> if (error) {
> return error;
> }
>
> - ofpbuf_clear(&actions);
> - error = add_internal_flow(ofproto, id++, &actions,
> + ofpbuf_clear(&ofpacts);
> + ofpact_put_END(&ofpacts);
> + error = add_internal_flow(ofproto, id++, &ofpacts,
> &ofproto->no_packet_in_rule);
> return error;
> }
> @@ -2864,8 +2866,7 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
> action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci,
> rule, 0, packet);
> ctx.resubmit_stats = &stats;
> - xlate_actions(&ctx, rule->up.actions, rule->up.n_actions,
> - &odp_actions);
> + xlate_actions(&ctx, rule->up.ofpacts, &odp_actions);
>
> if (odp_actions.size) {
> struct dpif_execute *execute = &op->dpif_op.u.execute;
> @@ -3699,8 +3700,7 @@ facet_learn(struct facet *facet)
> facet->flow.vlan_tci,
> facet->rule, facet->tcp_flags, NULL);
> ctx.may_learn = true;
> - xlate_actions_for_side_effects(&ctx, facet->rule->up.actions,
> - facet->rule->up.n_actions);
> + xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts);
> }
>
> static void
> @@ -3761,10 +3761,15 @@ facet_account(struct facet *facet)
> static bool
> facet_is_controller_flow(struct facet *facet)
> {
> - return (facet
> - && facet->rule->up.n_actions == 1
> - && action_outputs_to_port(&facet->rule->up.actions[0],
> - htons(OFPP_CONTROLLER)));
> + if (facet) {
> + const struct ofpact *ofpact = facet->rule->up.ofpacts;
> +
> + if (ofpact->type == OFPACT_CONTROLLER &&
> + ofpact_next(ofpact)->type == OFPACT_END) {
> + return true;
> + }
> + }
> + return false;
> }
>
> /* Folds all of 'facet''s statistics into its rule. Also updates the
> @@ -3939,8 +3944,7 @@ facet_check_consistency(struct facet *facet)
>
> action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
> subfacet->initial_tci, rule, 0, NULL);
> - xlate_actions(&ctx, rule->up.actions, rule->up.n_actions,
> - &odp_actions);
> + xlate_actions(&ctx, rule->up.ofpacts, &odp_actions);
>
> if (subfacet->path == SF_NOT_INSTALLED) {
> /* This only happens if the datapath reported an error when we
> @@ -4049,8 +4053,7 @@ facet_revalidate(struct facet *facet)
>
> action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
> subfacet->initial_tci, new_rule, 0, NULL);
> - xlate_actions(&ctx, new_rule->up.actions, new_rule->up.n_actions,
> - &odp_actions);
> + xlate_actions(&ctx, new_rule->up.ofpacts, &odp_actions);
>
> slow = (subfacet->slow & SLOW_MATCH) | ctx.slow;
> if (subfacet_should_install(subfacet, slow, &odp_actions)) {
> @@ -4179,7 +4182,7 @@ flow_push_stats(struct rule_dpif *rule,
> action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, rule,
> 0, NULL);
> ctx.resubmit_stats = stats;
> - xlate_actions_for_side_effects(&ctx, rule->up.actions, rule->up.n_actions);
> + xlate_actions_for_side_effects(&ctx, rule->up.ofpacts);
> }
>
> /* Subfacets. */
> @@ -4339,7 +4342,7 @@ subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
>
> action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
> rule, 0, packet);
> - xlate_actions(&ctx, rule->up.actions, rule->up.n_actions, odp_actions);
> + xlate_actions(&ctx, rule->up.ofpacts, odp_actions);
> facet->tags = ctx.tags;
> facet->has_learn = ctx.has_learn;
> facet->has_normal = ctx.has_normal;
> @@ -4576,8 +4579,8 @@ rule_construct(struct rule *rule_)
> uint8_t table_id;
> enum ofperr error;
>
> - error = validate_actions(rule->up.actions, rule->up.n_actions,
> - &rule->up.cr.flow, ofproto->max_ports);
> + error = ofpacts_check(rule->up.ofpacts,
> + &rule->up.cr.flow, ofproto->max_ports);
> if (error) {
> return error;
> }
> @@ -4669,7 +4672,7 @@ rule_execute(struct rule *rule_, const struct flow *flow,
> action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
> rule, stats.tcp_flags, packet);
> ctx.resubmit_stats = &stats;
> - xlate_actions(&ctx, rule->up.actions, rule->up.n_actions, &odp_actions);
> + xlate_actions(&ctx, rule->up.ofpacts, &odp_actions);
>
> execute_odp_actions(ofproto, flow, odp_actions.data,
> odp_actions.size, packet);
> @@ -4686,8 +4689,8 @@ rule_modify_actions(struct rule *rule_)
> struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
> enum ofperr error;
>
> - error = validate_actions(rule->up.actions, rule->up.n_actions,
> - &rule->up.cr.flow, ofproto->max_ports);
> + error = ofpacts_check(rule->up.ofpacts, &rule->up.cr.flow,
> + ofproto->max_ports);
> if (error) {
> ofoperation_complete(rule->up.pending, error);
> return;
> @@ -4740,8 +4743,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
>
> /* OpenFlow to datapath action translation. */
>
> -static void do_xlate_actions(const union ofp_action *in, size_t n_in,
> - struct action_xlate_ctx *ctx);
> +static void do_xlate_actions(const struct ofpact *, struct action_xlate_ctx *);
> static void xlate_normal(struct action_xlate_ctx *);
>
> /* Composes an ODP action for a "slow path" action for 'flow' within 'ofproto'.
> @@ -4987,7 +4989,7 @@ xlate_table_action(struct action_xlate_ctx *ctx,
>
> ctx->recurse++;
> ctx->rule = rule;
> - do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx);
> + do_xlate_actions(rule->up.ofpacts, ctx);
> ctx->rule = old_rule;
> ctx->recurse--;
> }
> @@ -5003,16 +5005,21 @@ xlate_table_action(struct action_xlate_ctx *ctx,
> }
>
> static void
> -xlate_resubmit_table(struct action_xlate_ctx *ctx,
> - const struct nx_action_resubmit *nar)
> +xlate_ofpact_resubmit(struct action_xlate_ctx *ctx,
> + const struct ofpact_resubmit *resubmit)
> {
> uint16_t in_port;
> uint8_t table_id;
>
> - in_port = (nar->in_port == htons(OFPP_IN_PORT)
> - ? ctx->flow.in_port
> - : ntohs(nar->in_port));
> - table_id = nar->table == 255 ? ctx->table_id : nar->table;
> + in_port = resubmit->in_port;
> + if (in_port == OFPP_IN_PORT) {
> + in_port = ctx->flow.in_port;
> + }
> +
> + table_id = resubmit->table_id;
> + if (table_id == 255) {
> + table_id = ctx->table_id;
> + }
>
> xlate_table_action(ctx, in_port, table_id);
> }
> @@ -5125,8 +5132,8 @@ compose_dec_ttl(struct action_xlate_ctx *ctx)
> }
>
> static void
> -xlate_output_action__(struct action_xlate_ctx *ctx,
> - uint16_t port, uint16_t max_len)
> +xlate_output_action(struct action_xlate_ctx *ctx,
> + uint16_t port, uint16_t max_len)
> {
> uint16_t prev_nf_output_iface = ctx->nf_output_iface;
>
> @@ -5173,44 +5180,32 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
>
> static void
> xlate_output_reg_action(struct action_xlate_ctx *ctx,
> - const struct nx_action_output_reg *naor)
> + const struct ofpact_output_reg *or)
> {
> - struct mf_subfield src;
> - uint64_t ofp_port;
> -
> - nxm_decode(&src, naor->src, naor->ofs_nbits);
> - ofp_port = mf_get_subfield(&src, &ctx->flow);
> -
> - if (ofp_port <= UINT16_MAX) {
> - xlate_output_action__(ctx, ofp_port, ntohs(naor->max_len));
> + uint64_t port = mf_get_subfield(&or->src, &ctx->flow);
> + if (port <= UINT16_MAX) {
> + xlate_output_action(ctx, port, or->max_len);
> }
> }
>
> static void
> -xlate_output_action(struct action_xlate_ctx *ctx,
> - const struct ofp_action_output *oao)
> -{
> - xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len));
> -}
> -
> -static void
> xlate_enqueue_action(struct action_xlate_ctx *ctx,
> - const struct ofp_action_enqueue *oae)
> + const struct ofpact_enqueue *enqueue)
> {
> - uint16_t ofp_port;
> + uint16_t ofp_port = enqueue->port;
> + uint32_t queue_id = enqueue->queue;
> uint32_t flow_priority, priority;
> int error;
>
> - error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id),
> - &priority);
> + /* Translate queue to priority. */
> + error = dpif_queue_to_priority(ctx->ofproto->dpif, queue_id, &priority);
> if (error) {
> /* Fall back to ordinary output action. */
> - xlate_output_action__(ctx, ntohs(oae->port), 0);
> + xlate_output_action(ctx, enqueue->port, 0);
> return;
> }
>
> - /* Figure out datapath output port. */
> - ofp_port = ntohs(oae->port);
> + /* Check output port. */
> if (ofp_port == OFPP_IN_PORT) {
> ofp_port = ctx->flow.in_port;
> } else if (ofp_port == ctx->flow.in_port) {
> @@ -5232,21 +5227,16 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx,
> }
>
> static void
> -xlate_set_queue_action(struct action_xlate_ctx *ctx,
> - const struct nx_action_set_queue *nasq)
> +xlate_set_queue_action(struct action_xlate_ctx *ctx, uint32_t queue_id)
> {
> - uint32_t priority;
> - int error;
> + uint32_t skb_priority;
>
> - error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(nasq->queue_id),
> - &priority);
> - if (error) {
> - /* Couldn't translate queue to a priority, so ignore. A warning
> + if (!dpif_queue_to_priority(ctx->ofproto->dpif, queue_id, &skb_priority)) {
> + ctx->flow.skb_priority = skb_priority;
> + } else {
> + /* Couldn't translate queue to a priority. Nothing to do. A warning
> * has already been logged. */
> - return;
> }
> -
> - ctx->flow.skb_priority = priority;
> }
>
> struct xlate_reg_state {
> @@ -5256,9 +5246,9 @@ struct xlate_reg_state {
>
> static void
> xlate_autopath(struct action_xlate_ctx *ctx,
> - const struct nx_action_autopath *naa)
> + const struct ofpact_autopath *ap)
> {
> - uint16_t ofp_port = ntohl(naa->id);
> + uint16_t ofp_port = ap->port;
> struct ofport_dpif *port = get_ofp_port(ctx->ofproto, ofp_port);
>
> if (!port || !port->bundle) {
> @@ -5271,7 +5261,7 @@ xlate_autopath(struct action_xlate_ctx *ctx,
> ofp_port = slave->up.ofp_port;
> }
> }
> - autopath_execute(naa, &ctx->flow, ofp_port);
> + nxm_reg_load(&ap->dst, ofp_port, &ctx->flow);
> }
>
> static bool
> @@ -5297,14 +5287,31 @@ slave_enabled_cb(uint16_t ofp_port, void *ofproto_)
> }
>
> static void
> +xlate_bundle_action(struct action_xlate_ctx *ctx,
> + const struct ofpact_bundle *bundle)
> +{
> + uint16_t port;
> +
> + port = bundle_execute(bundle, &ctx->flow, slave_enabled_cb, ctx->ofproto);
> + if (bundle->dst.field) {
> + nxm_reg_load(&bundle->dst, port, &ctx->flow);
> + } else {
> + xlate_output_action(ctx, port, 0);
> + }
> +}
> +
> +static void
> xlate_learn_action(struct action_xlate_ctx *ctx,
> - const struct nx_action_learn *learn)
> + const struct ofpact_learn *learn)
> {
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> struct ofputil_flow_mod fm;
> + uint64_t ofpacts_stub[1024 / 8];
> + struct ofpbuf ofpacts;
> int error;
>
> - learn_execute(learn, &ctx->flow, &fm);
> + ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
> + learn_execute(learn, &ctx->flow, &fm, &ofpacts);
>
> error = ofproto_flow_mod(&ctx->ofproto->up, &fm);
> if (error && !VLOG_DROP_WARN(&rl)) {
> @@ -5312,7 +5319,7 @@ xlate_learn_action(struct action_xlate_ctx *ctx,
> ofperr_get_name(error));
> }
>
> - free(fm.actions);
> + ofpbuf_uninit(&ofpacts);
> }
>
> /* Reduces '*timeout' to no more than 'max'. A value of zero in either case
> @@ -5327,13 +5334,13 @@ reduce_timeout(uint16_t max, uint16_t *timeout)
>
> static void
> xlate_fin_timeout(struct action_xlate_ctx *ctx,
> - const struct nx_action_fin_timeout *naft)
> + const struct ofpact_fin_timeout *oft)
> {
> if (ctx->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
> struct rule_dpif *rule = ctx->rule;
>
> - reduce_timeout(ntohs(naft->fin_idle_timeout), &rule->up.idle_timeout);
> - reduce_timeout(ntohs(naft->fin_hard_timeout), &rule->up.hard_timeout);
> + reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout);
> + reduce_timeout(oft->fin_hard_timeout, &rule->up.hard_timeout);
> }
> }
>
> @@ -5359,13 +5366,11 @@ may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
> }
>
> static void
> -do_xlate_actions(const union ofp_action *in, size_t n_in,
> - struct action_xlate_ctx *ctx)
> +do_xlate_actions(const struct ofpact *ofpacts, struct action_xlate_ctx *ctx)
> {
> const struct ofport_dpif *port;
> - const union ofp_action *ia;
> bool was_evictable = true;
> - size_t left;
> + const struct ofpact *a;
>
> port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
> if (port && !may_receive(port, ctx)) {
> @@ -5378,184 +5383,149 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
> was_evictable = ctx->rule->up.evictable;
> ctx->rule->up.evictable = false;
> }
> - OFPUTIL_ACTION_FOR_EACH_UNSAFE (ia, left, in, n_in) {
> - const struct ofp_action_dl_addr *oada;
> - const struct nx_action_resubmit *nar;
> - const struct nx_action_set_tunnel *nast;
> - const struct nx_action_set_queue *nasq;
> - const struct nx_action_multipath *nam;
> - const struct nx_action_autopath *naa;
> - const struct nx_action_bundle *nab;
> - const struct nx_action_output_reg *naor;
> - const struct nx_action_controller *nac;
> - enum ofputil_action_code code;
> - ovs_be64 tun_id;
> + OFPACT_FOR_EACH (a, ofpacts) {
> + struct ofpact_controller *controller;
>
> if (ctx->exit) {
> break;
> }
>
> - code = ofputil_decode_action_unsafe(ia);
> - switch (code) {
> - case OFPUTIL_ACTION_INVALID:
> - NOT_REACHED();
> + switch (a->type) {
> + case OFPACT_END:
> + goto out;
> +
> + case OFPACT_OUTPUT:
> + xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,
> + ofpact_get_OUTPUT(a)->max_len);
> + break;
> +
> + case OFPACT_CONTROLLER:
> + controller = ofpact_get_CONTROLLER(a);
> + execute_controller_action(ctx, controller->max_len,
> + controller->reason,
> + controller->controller_id);
> + break;
>
> - case OFPUTIL_OFPAT10_OUTPUT:
> - xlate_output_action(ctx, &ia->output);
> + case OFPACT_ENQUEUE:
> + xlate_enqueue_action(ctx, ofpact_get_ENQUEUE(a));
> break;
>
> - case OFPUTIL_OFPAT10_SET_VLAN_VID:
> + case OFPACT_SET_VLAN_VID:
> ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
> - ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI);
> + ctx->flow.vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
> + | htons(VLAN_CFI));
> break;
>
> - case OFPUTIL_OFPAT10_SET_VLAN_PCP:
> + case OFPACT_SET_VLAN_PCP:
> ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
> - ctx->flow.vlan_tci |= htons(
> - (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
> + ctx->flow.vlan_tci |= htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp
> + << VLAN_PCP_SHIFT)
> + | VLAN_CFI);
> break;
>
> - case OFPUTIL_OFPAT10_STRIP_VLAN:
> + case OFPACT_STRIP_VLAN:
> ctx->flow.vlan_tci = htons(0);
> break;
>
> - case OFPUTIL_OFPAT10_SET_DL_SRC:
> - oada = ((struct ofp_action_dl_addr *) ia);
> - memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN);
> + case OFPACT_SET_ETH_SRC:
> + memcpy(ctx->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac,
> + ETH_ADDR_LEN);
> break;
>
> - case OFPUTIL_OFPAT10_SET_DL_DST:
> - oada = ((struct ofp_action_dl_addr *) ia);
> - memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN);
> + case OFPACT_SET_ETH_DST:
> + memcpy(ctx->flow.dl_dst, ofpact_get_SET_ETH_DST(a)->mac,
> + ETH_ADDR_LEN);
> break;
>
> - case OFPUTIL_OFPAT10_SET_NW_SRC:
> - ctx->flow.nw_src = ia->nw_addr.nw_addr;
> + case OFPACT_SET_IPV4_SRC:
> + ctx->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
> break;
>
> - case OFPUTIL_OFPAT10_SET_NW_DST:
> - ctx->flow.nw_dst = ia->nw_addr.nw_addr;
> + case OFPACT_SET_IPV4_DST:
> + ctx->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
> break;
>
> - case OFPUTIL_OFPAT10_SET_NW_TOS:
> + case OFPACT_SET_IPV4_DSCP:
> /* OpenFlow 1.0 only supports IPv4. */
> if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
> ctx->flow.nw_tos &= ~IP_DSCP_MASK;
> - ctx->flow.nw_tos |= ia->nw_tos.nw_tos & IP_DSCP_MASK;
> + ctx->flow.nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp;
> }
> break;
>
> - case OFPUTIL_OFPAT10_SET_TP_SRC:
> - ctx->flow.tp_src = ia->tp_port.tp_port;
> - break;
> -
> - case OFPUTIL_OFPAT10_SET_TP_DST:
> - ctx->flow.tp_dst = ia->tp_port.tp_port;
> + case OFPACT_SET_L4_SRC_PORT:
> + ctx->flow.tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
> break;
>
> - case OFPUTIL_OFPAT10_ENQUEUE:
> - xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
> + case OFPACT_SET_L4_DST_PORT:
> + ctx->flow.tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
> break;
>
> - case OFPUTIL_NXAST_RESUBMIT:
> - nar = (const struct nx_action_resubmit *) ia;
> - xlate_table_action(ctx, ntohs(nar->in_port), ctx->table_id);
> + case OFPACT_RESUBMIT:
> + xlate_ofpact_resubmit(ctx, ofpact_get_RESUBMIT(a));
> break;
>
> - case OFPUTIL_NXAST_RESUBMIT_TABLE:
> - xlate_resubmit_table(ctx, (const struct nx_action_resubmit *) ia);
> + case OFPACT_SET_TUNNEL:
> + ctx->flow.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
> break;
>
> - case OFPUTIL_NXAST_SET_TUNNEL:
> - nast = (const struct nx_action_set_tunnel *) ia;
> - tun_id = htonll(ntohl(nast->tun_id));
> - ctx->flow.tun_id = tun_id;
> + case OFPACT_SET_QUEUE:
> + xlate_set_queue_action(ctx, ofpact_get_SET_QUEUE(a)->queue_id);
> break;
>
> - case OFPUTIL_NXAST_SET_QUEUE:
> - nasq = (const struct nx_action_set_queue *) ia;
> - xlate_set_queue_action(ctx, nasq);
> - break;
> -
> - case OFPUTIL_NXAST_POP_QUEUE:
> + case OFPACT_POP_QUEUE:
> ctx->flow.skb_priority = ctx->orig_skb_priority;
> break;
>
> - case OFPUTIL_NXAST_REG_MOVE:
> - nxm_execute_reg_move((const struct nx_action_reg_move *) ia,
> - &ctx->flow);
> + case OFPACT_REG_MOVE:
> + nxm_execute_reg_move(ofpact_get_REG_MOVE(a), &ctx->flow);
> break;
>
> - case OFPUTIL_NXAST_REG_LOAD:
> - nxm_execute_reg_load((const struct nx_action_reg_load *) ia,
> - &ctx->flow);
> + case OFPACT_REG_LOAD:
> + nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
> break;
>
> - case OFPUTIL_NXAST_NOTE:
> - /* Nothing to do. */
> - break;
> -
> - case OFPUTIL_NXAST_SET_TUNNEL64:
> - tun_id = ((const struct nx_action_set_tunnel64 *) ia)->tun_id;
> - ctx->flow.tun_id = tun_id;
> + case OFPACT_DEC_TTL:
> + if (compose_dec_ttl(ctx)) {
> + goto out;
> + }
> break;
>
> - case OFPUTIL_NXAST_MULTIPATH:
> - nam = (const struct nx_action_multipath *) ia;
> - multipath_execute(nam, &ctx->flow);
> + case OFPACT_NOTE:
> + /* Nothing to do. */
> break;
>
> - case OFPUTIL_NXAST_AUTOPATH:
> - naa = (const struct nx_action_autopath *) ia;
> - xlate_autopath(ctx, naa);
> + case OFPACT_MULTIPATH:
> + multipath_execute(ofpact_get_MULTIPATH(a), &ctx->flow);
> break;
>
> - case OFPUTIL_NXAST_BUNDLE:
> - ctx->ofproto->has_bundle_action = true;
> - nab = (const struct nx_action_bundle *) ia;
> - xlate_output_action__(ctx, bundle_execute(nab, &ctx->flow,
> - slave_enabled_cb,
> - ctx->ofproto), 0);
> + case OFPACT_AUTOPATH:
> + xlate_autopath(ctx, ofpact_get_AUTOPATH(a));
> break;
>
> - case OFPUTIL_NXAST_BUNDLE_LOAD:
> + case OFPACT_BUNDLE:
> ctx->ofproto->has_bundle_action = true;
> - nab = (const struct nx_action_bundle *) ia;
> - bundle_execute_load(nab, &ctx->flow, slave_enabled_cb,
> - ctx->ofproto);
> + xlate_bundle_action(ctx, ofpact_get_BUNDLE(a));
> break;
>
> - case OFPUTIL_NXAST_OUTPUT_REG:
> - naor = (const struct nx_action_output_reg *) ia;
> - xlate_output_reg_action(ctx, naor);
> + case OFPACT_OUTPUT_REG:
> + xlate_output_reg_action(ctx, ofpact_get_OUTPUT_REG(a));
> break;
>
> - case OFPUTIL_NXAST_LEARN:
> + case OFPACT_LEARN:
> ctx->has_learn = true;
> if (ctx->may_learn) {
> - xlate_learn_action(ctx, (const struct nx_action_learn *) ia);
> + xlate_learn_action(ctx, ofpact_get_LEARN(a));
> }
> break;
>
> - case OFPUTIL_NXAST_DEC_TTL:
> - if (compose_dec_ttl(ctx)) {
> - goto out;
> - }
> - break;
> -
> - case OFPUTIL_NXAST_EXIT:
> + case OFPACT_EXIT:
> ctx->exit = true;
> break;
>
> - case OFPUTIL_NXAST_FIN_TIMEOUT:
> + case OFPACT_FIN_TIMEOUT:
> ctx->has_fin_timeout = true;
> - xlate_fin_timeout(ctx, (const struct nx_action_fin_timeout *) ia);
> - break;
> -
> - case OFPUTIL_NXAST_CONTROLLER:
> - nac = (const struct nx_action_controller *) ia;
> - execute_controller_action(ctx, ntohs(nac->max_len), nac->reason,
> - ntohs(nac->controller_id));
> + xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
> break;
> }
> }
> @@ -5594,8 +5564,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
> /* Translates the 'n_in' "union ofp_action"s in 'in' into datapath actions in
> * 'odp_actions', using 'ctx'. */
> static void
> -xlate_actions(struct action_xlate_ctx *ctx,
> - const union ofp_action *in, size_t n_in,
> +xlate_actions(struct action_xlate_ctx *ctx, const struct ofpact *ofpacts,
> struct ofpbuf *odp_actions)
> {
> /* Normally false. Set to true if we ever hit MAX_RESUBMIT_RECURSION, so
> @@ -5665,7 +5634,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
> ovs_be16 initial_tci = ctx->base_flow.vlan_tci;
>
> add_sflow_action(ctx);
> - do_xlate_actions(in, n_in, ctx);
> + do_xlate_actions(ofpacts, ctx);
>
> if (ctx->max_resubmit_trigger && !ctx->resubmit_hook) {
> if (!hit_resubmit_limit) {
> @@ -5704,13 +5673,13 @@ xlate_actions(struct action_xlate_ctx *ctx,
> * using 'ctx', and discards the datapath actions. */
> static void
> xlate_actions_for_side_effects(struct action_xlate_ctx *ctx,
> - const union ofp_action *in, size_t n_in)
> + const struct ofpact *in)
> {
> uint64_t odp_actions_stub[1024 / 8];
> struct ofpbuf odp_actions;
>
> ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
> - xlate_actions(ctx, in, n_in, &odp_actions);
> + xlate_actions(ctx, in, &odp_actions);
> ofpbuf_uninit(&odp_actions);
> }
>
> @@ -6370,8 +6339,7 @@ set_frag_handling(struct ofproto *ofproto_,
>
> static enum ofperr
> packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
> - const struct flow *flow,
> - const union ofp_action *ofp_actions, size_t n_ofp_actions)
> + const struct flow *flow, const struct ofpact *ofpacts)
> {
> struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
> enum ofperr error;
> @@ -6380,8 +6348,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
> return OFPERR_NXBRC_BAD_IN_PORT;
> }
>
> - error = validate_actions(ofp_actions, n_ofp_actions, flow,
> - ofproto->max_ports);
> + error = ofpacts_check(ofpacts, flow, ofproto->max_ports);
> if (!error) {
> struct odputil_keybuf keybuf;
> struct dpif_flow_stats stats;
> @@ -6403,7 +6370,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
>
> ofpbuf_use_stub(&odp_actions,
> odp_actions_stub, sizeof odp_actions_stub);
> - xlate_actions(&ctx, ofp_actions, n_ofp_actions, &odp_actions);
> + xlate_actions(&ctx, ofpacts, &odp_actions);
> dpif_execute(ofproto->dpif, key.data, key.size,
> odp_actions.data, odp_actions.size, packet);
> ofpbuf_uninit(&odp_actions);
> @@ -6560,7 +6527,7 @@ trace_format_rule(struct ds *result, uint8_t table_id, int level,
>
> ds_put_char_multiple(result, '\t', level);
> ds_put_cstr(result, "OpenFlow ");
> - ofp_print_actions(result, rule->up.actions, rule->up.n_actions);
> + ofpacts_format(rule->up.ofpacts, result);
> ds_put_char(result, '\n');
> }
>
> @@ -6768,8 +6735,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
> action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_tci,
> rule, tcp_flags, packet);
> trace.ctx.resubmit_hook = trace_resubmit;
> - xlate_actions(&trace.ctx, rule->up.actions, rule->up.n_actions,
> - &odp_actions);
> + xlate_actions(&trace.ctx, rule->up.ofpacts, &odp_actions);
>
> ds_put_char(ds, '\n');
> trace_format_flow(ds, 0, "Final flow", &trace);
> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
> index 2cbb9ae..ae9ace5 100644
> --- a/ofproto/ofproto-provider.h
> +++ b/ofproto/ofproto-provider.h
> @@ -29,6 +29,7 @@
> #include "shash.h"
> #include "timeval.h"
>
> +struct ofpact;
> struct ofputil_flow_mod;
> struct simap;
>
> @@ -184,8 +185,8 @@ struct rule {
> struct heap_node evg_node; /* In eviction_group's "rules" heap. */
> struct eviction_group *eviction_group; /* NULL if not in any group. */
>
> - union ofp_action *actions; /* OpenFlow actions. */
> - int n_actions; /* Number of elements in actions[]. */
> + struct ofpact *ofpacts; /* "OFPACT_*"s. Ends with OFPACT_END. */
> + unsigned int ofpacts_len; /* Size of 'ofpacts', in bytes. */
> };
>
> static inline struct rule *
> @@ -781,13 +782,11 @@ struct ofproto_class {
> * registers, then it is an error if 'rule->cr' does not wildcard all
> * registers.
> *
> - * - Validate that 'rule->actions' and 'rule->n_actions' are well-formed
> - * OpenFlow actions that the datapath can correctly implement. The
> - * validate_actions() function (in ofp-util.c) can be useful as a model
> - * for action validation, but it accepts all of the OpenFlow actions
> - * that OVS understands. If your ofproto implementation only
> - * implements a subset of those, then you should implement your own
> - * action validation.
> + * - Validate that 'rule->ofpacts' is a sequence of well-formed actions
> + * that the datapath can correctly implement. If your ofproto
> + * implementation only implements a subset of the actions that Open
> + * vSwitch understands, then you should implement your own action
> + * validation.
> *
> * - If the rule is valid, update the datapath flow table, adding the new
> * rule or replacing the existing one.
> @@ -918,14 +917,13 @@ struct ofproto_class {
> enum ofp_config_flags frag_handling);
>
> /* Implements the OpenFlow OFPT_PACKET_OUT command. The datapath should
> - * execute the 'n_actions' in the 'actions' array on 'packet'.
> + * execute the sequence of 'ofpacts' (which ends with OFPACT_END).
> *
> - * The caller retains ownership of 'packet', so ->packet_out() should not
> - * modify or free it.
> + * The caller retains ownership of 'packet' and of 'ofpacts', so
> + * ->packet_out() should not modify or free them.
> *
> - * This function must validate that the 'n_actions' elements in 'actions'
> - * are well-formed OpenFlow actions that can be correctly implemented by
> - * the datapath. If not, then it should return an OpenFlow error code.
> + * This function must validate that it can implement 'ofpacts'. If not,
> + * then it should return an OpenFlow error code.
> *
> * 'flow' reflects the flow information for 'packet'. All of the
> * information in 'flow' is extracted from 'packet', except for
> @@ -957,8 +955,7 @@ struct ofproto_class {
> * Returns 0 if successful, otherwise an OpenFlow error code. */
> enum ofperr (*packet_out)(struct ofproto *ofproto, struct ofpbuf *packet,
> const struct flow *flow,
> - const union ofp_action *actions,
> - size_t n_actions);
> + const struct ofpact *ofpacts);
>
> /* ## ------------------------- ## */
> /* ## OFPP_NORMAL configuration ## */
> @@ -1195,7 +1192,7 @@ BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS);
>
> int ofproto_flow_mod(struct ofproto *, const struct ofputil_flow_mod *);
> void ofproto_add_flow(struct ofproto *, const struct cls_rule *,
> - const union ofp_action *, size_t n_actions);
> + const struct ofpact *ofpacts, size_t ofpacts_len);
> bool ofproto_delete_flow(struct ofproto *, const struct cls_rule *);
> void ofproto_flush_flows(struct ofproto *);
>
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 1a2f712..0d3fa1b 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -32,6 +32,7 @@
> #include "meta-flow.h"
> #include "netdev.h"
> #include "nx-match.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-print.h"
> #include "ofp-util.h"
> @@ -118,8 +119,8 @@ struct ofoperation {
> struct rule *rule; /* Rule being operated upon. */
> enum ofoperation_type type; /* Type of operation. */
> struct rule *victim; /* OFOPERATION_ADDING: Replaced rule. */
> - union ofp_action *actions; /* OFOPERATION_MODIFYING: Replaced actions. */
> - int n_actions; /* OFOPERATION_MODIFYING: # of old actions. */
> + struct ofpact *ofpacts; /* OFOPERATION_MODIFYING: Replaced actions. */
> + size_t ofpacts_len; /* OFOPERATION_MODIFYING: Bytes of ofpacts. */
> ovs_be64 flow_cookie; /* Rule's old flow cookie. */
> };
>
> @@ -1378,27 +1379,28 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port)
> * (0...65535, inclusive) then the flow will be visible to OpenFlow
> * controllers; otherwise, it will be hidden.
> *
> - * The caller retains ownership of 'cls_rule' and 'actions'.
> + * The caller retains ownership of 'cls_rule' and 'ofpacts'.
> *
> * This is a helper function for in-band control and fail-open. */
> void
> ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule,
> - const union ofp_action *actions, size_t n_actions)
> + const struct ofpact *ofpacts, size_t ofpacts_len)
> {
> const struct rule *rule;
>
> rule = rule_from_cls_rule(classifier_find_rule_exactly(
> &ofproto->tables[0].cls, cls_rule));
> - if (!rule || !ofputil_actions_equal(rule->actions, rule->n_actions,
> - actions, n_actions)) {
> + if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
> + ofpacts, ofpacts_len)) {
> struct ofputil_flow_mod fm;
>
> memset(&fm, 0, sizeof fm);
> fm.cr = *cls_rule;
> fm.buffer_id = UINT32_MAX;
> - fm.actions = (union ofp_action *) actions;
> - fm.n_actions = n_actions;
> + fm.ofpacts = xmemdup(ofpacts, ofpacts_len);
> + fm.ofpacts_len = ofpacts_len;
> add_flow(ofproto, NULL, &fm, NULL);
> + free(fm.ofpacts);
> }
> }
>
> @@ -1857,7 +1859,7 @@ static void
> ofproto_rule_destroy__(struct rule *rule)
> {
> if (rule) {
> - free(rule->actions);
> + free(rule->ofpacts);
> rule->ofproto->ofproto_class->rule_dealloc(rule);
> }
> }
> @@ -1879,23 +1881,11 @@ ofproto_rule_destroy(struct rule *rule)
> }
>
> /* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
> - * that outputs to 'out_port' (output to OFPP_FLOOD and OFPP_ALL doesn't
> - * count). */
> + * that outputs to 'port' (output to OFPP_FLOOD and OFPP_ALL doesn't count). */
> static bool
> -rule_has_out_port(const struct rule *rule, uint16_t out_port)
> +rule_has_out_port(const struct rule *rule, uint16_t port)
> {
> - const union ofp_action *oa;
> - size_t left;
> -
> - if (out_port == OFPP_NONE) {
> - return true;
> - }
> - OFPUTIL_ACTION_FOR_EACH_UNSAFE (oa, left, rule->actions, rule->n_actions) {
> - if (action_outputs_to_port(oa, htons(out_port))) {
> - return true;
> - }
> - }
> - return false;
> + return port == OFPP_NONE || ofpacts_output_to_port(rule->ofpacts, port);
> }
>
> /* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s
> @@ -2052,6 +2042,8 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
> struct ofproto *p = ofconn_get_ofproto(ofconn);
> struct ofputil_packet_out po;
> struct ofpbuf *payload;
> + uint64_t ofpacts_stub[1024 / 8];
> + struct ofpbuf ofpacts;
> struct flow flow;
> enum ofperr error;
>
> @@ -2059,20 +2051,21 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
>
> error = reject_slave_controller(ofconn);
> if (error) {
> - return error;
> + goto exit;
> }
>
> /* Decode message. */
> - error = ofputil_decode_packet_out(&po, opo);
> + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
> + error = ofputil_decode_packet_out(&po, opo, &ofpacts);
> if (error) {
> - return error;
> + goto exit_free_ofpacts;
> }
>
> /* Get payload. */
> if (po.buffer_id != UINT32_MAX) {
> error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
> if (error || !payload) {
> - return error;
> + goto exit_free_ofpacts;
> }
> } else {
> payload = xmalloc(sizeof *payload);
> @@ -2081,10 +2074,12 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
>
> /* Send out packet. */
> flow_extract(payload, 0, 0, po.in_port, &flow);
> - error = p->ofproto_class->packet_out(p, payload, &flow,
> - po.actions, po.n_actions);
> + error = p->ofproto_class->packet_out(p, payload, &flow, po.ofpacts);
> ofpbuf_delete(payload);
>
> +exit_free_ofpacts:
> + ofpbuf_uninit(&ofpacts);
> +exit:
> return error;
> }
>
> @@ -2486,8 +2481,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
> fs.hard_age = age_secs(now - rule->modified);
> ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
> &fs.byte_count);
> - fs.actions = rule->actions;
> - fs.n_actions = rule->n_actions;
> + fs.ofpacts = rule->ofpacts;
> ofputil_append_flow_stats_reply(&fs, &replies);
> }
> ofconn_send_replies(ofconn, &replies);
> @@ -2513,8 +2507,8 @@ flow_stats_ds(struct rule *rule, struct ds *results)
> ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
> cls_rule_format(&rule->cr, results);
> ds_put_char(results, ',');
> - if (rule->n_actions > 0) {
> - ofp_print_actions(results, rule->actions, rule->n_actions);
> + if (rule->ofpacts->type != OFPACT_END) {
> + ofpacts_format(rule->ofpacts, results);
> } else {
> ds_put_cstr(results, "drop");
> }
> @@ -2763,6 +2757,9 @@ is_flow_deletion_pending(const struct ofproto *ofproto,
> * error code on failure, or OFPROTO_POSTPONE if the operation cannot be
> * initiated now but may be retried later.
> *
> + * Upon successful return, takes ownership of 'fm->ofpacts'. On failure,
> + * ownership remains with the caller.
> + *
> * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
> * if any. */
> static enum ofperr
> @@ -2831,8 +2828,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
> rule->hard_timeout = fm->hard_timeout;
> rule->table_id = table - ofproto->tables;
> rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
> - rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions);
> - rule->n_actions = fm->n_actions;
> + rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
> + rule->ofpacts_len = fm->ofpacts_len;
> rule->evictable = true;
> rule->eviction_group = NULL;
>
> @@ -2914,14 +2911,14 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
> continue;
> }
>
> - if (!ofputil_actions_equal(fm->actions, fm->n_actions,
> - rule->actions, rule->n_actions)) {
> + if (!ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
> + rule->ofpacts, rule->ofpacts_len)) {
> ofoperation_create(group, rule, OFOPERATION_MODIFY);
> - rule->pending->actions = rule->actions;
> - rule->pending->n_actions = rule->n_actions;
> - rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions);
> - rule->n_actions = fm->n_actions;
> - ofproto->ofproto_class->rule_modify_actions(rule);
> + rule->pending->ofpacts = rule->ofpacts;
> + rule->pending->ofpacts_len = rule->ofpacts_len;
> + rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
> + rule->ofpacts_len = fm->ofpacts_len;
> + rule->ofproto->ofproto_class->rule_modify_actions(rule);
> } else {
> rule->modified = time_msec();
> }
> @@ -3119,30 +3116,35 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
> {
> struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
> struct ofputil_flow_mod fm;
> + uint64_t ofpacts_stub[1024 / 8];
> + struct ofpbuf ofpacts;
> enum ofperr error;
> long long int now;
>
> error = reject_slave_controller(ofconn);
> if (error) {
> - return error;
> + goto exit;
> }
>
> - error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn));
> + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
> + error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
> + &ofpacts);
> if (error) {
> - return error;
> + goto exit_free_ofpacts;
> }
>
> /* We do not support the OpenFlow 1.0 emergency flow cache, which is not
> * required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. */
> if (fm.flags & OFPFF_EMERG) {
> - /* There isn't a good fit for an error code, so just state that the
> - * flow table is full. */
> - return OFPERR_OFPFMFC_ALL_TABLES_FULL;
> + /* We do not support the emergency flow cache. It will hopefully get
> + * dropped from OpenFlow in the near future. There is no good error
> + * code, so just state that the flow table is full. */
> + error = OFPERR_OFPFMFC_ALL_TABLES_FULL;
> + } else {
> + error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
> }
> -
> - error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
> if (error) {
> - return error;
> + goto exit_free_ofpacts;
> }
>
> /* Record the operation for logging a summary report. */
> @@ -3171,7 +3173,10 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
> }
> ofproto->last_op = now;
>
> - return 0;
> +exit_free_ofpacts:
> + ofpbuf_uninit(&ofpacts);
> +exit:
> + return error;
> }
>
> static enum ofperr
> @@ -3607,7 +3612,7 @@ ofoperation_destroy(struct ofoperation *op)
> hmap_remove(&group->ofproto->deletions, &op->hmap_node);
> }
> list_remove(&op->group_node);
> - free(op->actions);
> + free(op->ofpacts);
> free(op);
>
> if (list_is_empty(&group->ops) && !list_is_empty(&group->ofproto_node)) {
> @@ -3707,10 +3712,10 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error)
> if (!error) {
> rule->modified = time_msec();
> } else {
> - free(rule->actions);
> - rule->actions = op->actions;
> - rule->n_actions = op->n_actions;
> - op->actions = NULL;
> + free(rule->ofpacts);
> + rule->ofpacts = op->ofpacts;
> + rule->ofpacts_len = op->ofpacts_len;
> + op->ofpacts = NULL;
> }
> break;
>
> diff --git a/tests/learn.at b/tests/learn.at
> index 9304861..da82f51 100644
> --- a/tests/learn.at
> +++ b/tests/learn.at
> @@ -10,7 +10,7 @@ AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
> [[usable protocols: any
> chosen protocol: OpenFlow10-table_id
> OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
> -OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[],load:0x000a->NXM_NX_REG0[5..10])
> +OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[],load:0xa->NXM_NX_REG0[5..10])
> OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,idle_timeout=10,hard_timeout=20,fin_idle_timeout=5,fin_hard_timeout=10,priority=10,cookie=0xfedcba9876543210,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
> ]])
> AT_CLEANUP
> @@ -42,7 +42,7 @@ ip,actions=learn(eth_type=0x800,OXM_OF_IPV4_DST[])
> AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
> [[usable protocols: any
> chosen protocol: OpenFlow10-table_id
> -OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x00000005->NXM_OF_IP_DST[])
> +OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x5->NXM_OF_IP_DST[])
> OFPT_FLOW_MOD (xid=0x2): ADD ip actions=learn(table=1,load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
> OFPT_FLOW_MOD (xid=0x3): ADD ip actions=learn(table=1,eth_type=0x800,NXM_OF_IP_DST[])
> ]])
> diff --git a/tests/test-bundle.c b/tests/test-bundle.c
> index 672c426..f2d9b82 100644
> --- a/tests/test-bundle.c
> +++ b/tests/test-bundle.c
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2011 Nicira, Inc.
> +/* Copyright (c) 2011, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -21,6 +21,7 @@
> #include <stdlib.h>
>
> #include "flow.h"
> +#include "ofp-actions.h"
> #include "ofpbuf.h"
> #include "random.h"
>
> @@ -64,22 +65,24 @@ slave_enabled_cb(uint16_t slave_id, void *aux)
> return slave ? slave->enabled : false;
> }
>
> -static struct nx_action_bundle *
> +static struct ofpact_bundle *
> parse_bundle_actions(char *actions)
> {
> - struct nx_action_bundle *nab;
> - struct ofpbuf b;
> + struct ofpact_bundle *bundle;
> + struct ofpbuf ofpacts;
> + struct ofpact *action;
>
> - ofpbuf_init(&b, 0);
> - bundle_parse_load(&b, actions);
> - nab = ofpbuf_steal_data(&b);
> - ofpbuf_uninit(&b);
> + ofpbuf_init(&ofpacts, 0);
> + bundle_parse_load(actions, &ofpacts);
> + action = ofpacts.data;
> + bundle = ofpact_get_BUNDLE(xmemdup(action, action->len));
> + ofpbuf_uninit(&ofpacts);
>
> - if (ntohs(nab->n_slaves) > MAX_SLAVES) {
> + if (bundle->n_slaves > MAX_SLAVES) {
> ovs_fatal(0, "At most %u slaves are supported", MAX_SLAVES);
> }
>
> - return nab;
> + return bundle;
> }
>
> static const char *
> @@ -101,7 +104,7 @@ int
> main(int argc, char *argv[])
> {
> bool ok = true;
> - struct nx_action_bundle *nab;
> + struct ofpact_bundle *bundle;
> struct flow *flows;
> size_t i, n_permute, old_n_enabled;
> struct slave_group sg;
> @@ -114,12 +117,12 @@ main(int argc, char *argv[])
> ovs_fatal(0, "usage: %s bundle_action", program_name);
> }
>
> - nab = parse_bundle_actions(argv[1]);
> + bundle = parse_bundle_actions(argv[1]);
>
> /* Generate 'slaves' array. */
> sg.n_slaves = 0;
> - for (i = 0; i < ntohs(nab->n_slaves); i++) {
> - uint16_t slave_id = bundle_get_slave(nab, i);
> + for (i = 0; i < bundle->n_slaves; i++) {
> + uint16_t slave_id = bundle->slaves[i];
>
> if (slave_lookup(&sg, slave_id)) {
> ovs_fatal(0, "Redundant slaves are not supported. ");
> @@ -136,10 +139,6 @@ main(int argc, char *argv[])
> flows[i].regs[0] = OFPP_NONE;
> }
>
> - if (bundle_check(nab, 1024, flows)) {
> - ovs_fatal(0, "Bundle action fails to check.");
> - }
> -
> /* Cycles through each possible liveness permutation for the given
> * n_slaves. The initial state is equivalent to all slaves down, so we
> * skip it by starting at i = 1. We do one extra iteration to cover
> @@ -188,23 +187,19 @@ main(int argc, char *argv[])
> uint16_t old_slave_id, ofp_port;
>
> old_slave_id = flow->regs[0];
> - ofp_port = bundle_execute(nab, flow, slave_enabled_cb, &sg);
> - bundle_execute_load(nab, flow, slave_enabled_cb, &sg);
> - if (flow->regs[0] != ofp_port) {
> - ovs_fatal(0, "bundle_execute_load() and bundle_execute() "
> - "disagree");
> - }
> + ofp_port = bundle_execute(bundle, flow, slave_enabled_cb, &sg);
> + flow->regs[0] = ofp_port;
>
> - if (flow->regs[0] != OFPP_NONE) {
> - slave_lookup(&sg, flow->regs[0])->flow_count++;
> + if (ofp_port != OFPP_NONE) {
> + slave_lookup(&sg, ofp_port)->flow_count++;
> }
>
> - if (old_slave_id != flow->regs[0]) {
> + if (old_slave_id != ofp_port) {
> changed++;
> }
> }
>
> - if (nab->algorithm == htons(NX_BD_ALG_ACTIVE_BACKUP)) {
> + if (bundle->algorithm == NX_BD_ALG_ACTIVE_BACKUP) {
> perfect = active == old_active ? 0.0 : 1.0;
> } else {
> if (old_n_enabled || n_enabled) {
> @@ -229,7 +224,7 @@ main(int argc, char *argv[])
> if (slave->enabled) {
> double perfect_fp;
>
> - if (nab->algorithm == htons(NX_BD_ALG_ACTIVE_BACKUP)) {
> + if (bundle->algorithm == NX_BD_ALG_ACTIVE_BACKUP) {
> perfect_fp = j == active ? 1.0 : 0.0;
> } else {
> perfect_fp = 1.0 / n_enabled;
> @@ -262,7 +257,7 @@ main(int argc, char *argv[])
> old_n_enabled = n_enabled;
> }
>
> - free(nab);
> + free(bundle);
> free(flows);
> return ok ? 0 : 1;
> }
> diff --git a/tests/test-multipath.c b/tests/test-multipath.c
> index 483eb3d..8a35567 100644
> --- a/tests/test-multipath.c
> +++ b/tests/test-multipath.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2010 Nicira, Inc.
> + * Copyright (c) 2010, 2012 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -25,6 +25,7 @@
> #include <stdlib.h>
>
> #include "flow.h"
> +#include "ofp-actions.h"
> #include "random.h"
> #include "util.h"
>
> @@ -32,7 +33,7 @@ int
> main(int argc, char *argv[])
> {
> enum { MP_MAX_LINKS = 63 };
> - struct nx_action_multipath mp;
> + struct ofpact_multipath mp;
> bool ok = true;
> int n;
>
> @@ -60,11 +61,11 @@ main(int argc, char *argv[])
>
> random_bytes(&flow, sizeof flow);
>
> - mp.max_link = htons(n - 1);
> + mp.max_link = n - 1;
> multipath_execute(&mp, &flow);
> old_link = flow.regs[0];
>
> - mp.max_link = htons(n);
> + mp.max_link = n;
> multipath_execute(&mp, &flow);
> new_link = flow.regs[0];
>
> @@ -91,7 +92,7 @@ main(int argc, char *argv[])
> "stddev/expected=%.4f\n",
> n, n + 1, disruption, perfect, distribution);
>
> - switch (ntohs(mp.algorithm)) {
> + switch (mp.algorithm) {
> case NX_MP_ALG_MODULO_N:
> if (disruption < (n < 2 ? .25 : .5)) {
> fprintf(stderr, "%d -> %d: disruption=%.2f < .5\n",
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index 7413455..e10b966 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -35,9 +35,9 @@
> #include "compiler.h"
> #include "dirs.h"
> #include "dynamic-string.h"
> -#include "netlink.h"
> #include "nx-match.h"
> #include "odp-util.h"
> +#include "ofp-actions.h"
> #include "ofp-errors.h"
> #include "ofp-parse.h"
> #include "ofp-print.h"
> @@ -861,7 +861,7 @@ do_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms)
> struct ofputil_flow_mod *fm = &fms[i];
>
> transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
> - free(fm->actions);
> + free(fm->ofpacts);
> }
> vconn_close(vconn);
> }
> @@ -1233,19 +1233,19 @@ static void
> do_packet_out(int argc, char *argv[])
> {
> struct ofputil_packet_out po;
> - struct ofpbuf actions;
> + struct ofpbuf ofpacts;
> struct vconn *vconn;
> int i;
>
> - ofpbuf_init(&actions, sizeof(union ofp_action));
> - parse_ofp_actions(argv[3], &actions);
> + ofpbuf_init(&ofpacts, 64);
> + parse_ofpacts(argv[3], &ofpacts);
>
> po.buffer_id = UINT32_MAX;
> po.in_port = (!strcasecmp(argv[2], "none") ? OFPP_NONE
> : !strcasecmp(argv[2], "local") ? OFPP_LOCAL
> : str_to_port_no(argv[1], argv[2]));
> - po.actions = actions.data;
> - po.n_actions = actions.size / sizeof(union ofp_action);
> + po.ofpacts = ofpacts.data;
> + po.ofpacts_len = ofpacts.size;
>
> open_vconn(argv[1], &vconn);
> for (i = 4; i < argc; i++) {
> @@ -1264,7 +1264,7 @@ do_packet_out(int argc, char *argv[])
> ofpbuf_delete(packet);
> }
> vconn_close(vconn);
> - ofpbuf_uninit(&actions);
> + ofpbuf_uninit(&ofpacts);
> }
>
> static void
> @@ -1482,8 +1482,8 @@ struct fte_version {
> uint16_t idle_timeout;
> uint16_t hard_timeout;
> uint16_t flags;
> - union ofp_action *actions;
> - size_t n_actions;
> + struct ofpact *ofpacts;
> + size_t ofpacts_len;
> };
>
> /* Frees 'version' and the data that it owns. */
> @@ -1491,7 +1491,7 @@ static void
> fte_version_free(struct fte_version *version)
> {
> if (version) {
> - free(version->actions);
> + free(version->ofpacts);
> free(version);
> }
> }
> @@ -1506,9 +1506,8 @@ fte_version_equals(const struct fte_version *a, const struct fte_version *b)
> return (a->cookie == b->cookie
> && a->idle_timeout == b->idle_timeout
> && a->hard_timeout == b->hard_timeout
> - && a->n_actions == b->n_actions
> - && !memcmp(a->actions, b->actions,
> - a->n_actions * sizeof *a->actions));
> + && ofpacts_equal(a->ofpacts, a->ofpacts_len,
> + b->ofpacts, b->ofpacts_len));
> }
>
> /* Prints 'version' on stdout. Expects the caller to have printed the rule
> @@ -1529,7 +1528,7 @@ fte_version_print(const struct fte_version *version)
> }
>
> ds_init(&s);
> - ofp_print_actions(&s, version->actions, version->n_actions);
> + ofpacts_format(version->ofpacts, &s);
> printf(" %s\n", ds_cstr(&s));
> ds_destroy(&s);
> }
> @@ -1617,8 +1616,8 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
> version->idle_timeout = fm.idle_timeout;
> version->hard_timeout = fm.hard_timeout;
> version->flags = fm.flags & (OFPFF_SEND_FLOW_REM | OFPFF_EMERG);
> - version->actions = fm.actions;
> - version->n_actions = fm.n_actions;
> + version->ofpacts = fm.ofpacts;
> + version->ofpacts_len = fm.ofpacts_len;
>
> usable_protocols &= ofputil_usable_protocols(&fm.cr);
>
> @@ -1684,10 +1683,14 @@ read_flows_from_switch(struct vconn *vconn,
> for (;;) {
> struct fte_version *version;
> struct ofputil_flow_stats fs;
> + struct ofpbuf ofpacts;
> int retval;
>
> - retval = ofputil_decode_flow_stats_reply(&fs, reply, false);
> + ofpbuf_init(&ofpacts, 64);
> + retval = ofputil_decode_flow_stats_reply(&fs, reply, false,
> + &ofpacts);
> if (retval) {
> + ofpbuf_uninit(&ofpacts);
> if (retval != EOF) {
> ovs_fatal(0, "parse error in reply");
> }
> @@ -1699,9 +1702,8 @@ read_flows_from_switch(struct vconn *vconn,
> version->idle_timeout = fs.idle_timeout;
> version->hard_timeout = fs.hard_timeout;
> version->flags = 0;
> - version->n_actions = fs.n_actions;
> - version->actions = xmemdup(fs.actions,
> - fs.n_actions * sizeof *fs.actions);
> + version->ofpacts = ofpbuf_steal_data(&ofpacts);
> + version->ofpacts_len = ofpacts.size;
>
> fte_insert(cls, &fs.rule, version, index);
> }
> @@ -1734,11 +1736,11 @@ fte_make_flow_mod(const struct fte *fte, int index, uint16_t command,
> fm.flags = version->flags;
> if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
> command == OFPFC_MODIFY_STRICT) {
> - fm.actions = version->actions;
> - fm.n_actions = version->n_actions;
> + fm.ofpacts = version->ofpacts;
> + fm.ofpacts_len = version->ofpacts_len;
> } else {
> - fm.actions = NULL;
> - fm.n_actions = 0;
> + fm.ofpacts = NULL;
> + fm.ofpacts_len = 0;
> }
>
> ofm = ofputil_encode_flow_mod(&fm, protocol);
> @@ -1891,7 +1893,7 @@ do_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
> ofp_print(stdout, msg->data, msg->size, verbosity);
> ofpbuf_delete(msg);
>
> - free(fm->actions);
> + free(fm->ofpacts);
> }
> }
>
> --
> 1.7.2.5
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list