-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_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;
-}
-