X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=df3377ae90e9315310d6934f0354a0189e1ed34e;hb=db5b4525b20e0fd6a079831638b5eb3f9fb131f2;hp=8721b191d811ded83bd3d283e8dde21e2410f5c4;hpb=5e9d0469fcaa30f4de0209392a1329b4c52d8d63;p=sliver-openvswitch.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 8721b191d..df3377ae9 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -21,6 +21,7 @@ #include #include #include "autopath.h" +#include "bundle.h" #include "byte-order.h" #include "classifier.h" #include "dynamic-string.h" @@ -725,8 +726,8 @@ ofputil_decode_msg_type(const struct ofp_header *oh, } if (error) { static const struct ofputil_msg_type ofputil_invalid_type = { - OFPUTIL_INVALID, - 0, "OFPUTIL_INVALID", + OFPUTIL_MSG_INVALID, + 0, "OFPUTIL_MSG_INVALID", 0, 0 }; @@ -974,7 +975,7 @@ ofputil_encode_flow_mod(const struct flow_mod *fm, ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg); ofputil_cls_rule_to_match(&fm->cr, &ofm->match); ofm->cookie = fm->cookie; - ofm->command = htons(fm->command); + ofm->command = htons(command); ofm->idle_timeout = htons(fm->idle_timeout); ofm->hard_timeout = htons(fm->hard_timeout); ofm->priority = htons(fm->cr.priority); @@ -1941,38 +1942,11 @@ make_echo_reply(const struct ofp_header *rq) return out; } -static int -check_action_exact_len(const union ofp_action *a, unsigned int len, - unsigned int required_len) -{ - if (len != required_len) { - VLOG_WARN_RL(&bad_ofmsg_rl, "action %"PRIu16" has invalid length " - "%"PRIu16" (must be %u)\n", - ntohs(a->type), ntohs(a->header.len), required_len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - return 0; -} - -static int -check_nx_action_exact_len(const struct nx_action_header *a, - unsigned int len, unsigned int required_len) -{ - if (len != required_len) { - VLOG_WARN_RL(&bad_ofmsg_rl, - "Nicira action %"PRIu16" has invalid length %"PRIu16" " - "(must be %u)\n", - ntohs(a->subtype), ntohs(a->len), required_len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - return 0; -} - /* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given * that the switch will never have more than 'max_ports' ports. Returns 0 if * 'port' is valid, otherwise an ofp_mkerr() return code. */ -static int -check_output_port(uint16_t port, int max_ports) +int +ofputil_check_output_port(uint16_t port, int max_ports) { switch (port) { case OFPP_IN_PORT: @@ -1988,208 +1962,243 @@ check_output_port(uint16_t port, int max_ports) if (port < max_ports) { return 0; } - VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port); return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); } } -/* Checks that 'action' is a valid OFPAT_ENQUEUE action, given that the switch - * will never have more than 'max_ports' ports. Returns 0 if 'port' is valid, - * otherwise an ofp_mkerr() return code. */ -static int -check_enqueue_action(const union ofp_action *a, unsigned int len, - int max_ports) +int +validate_actions(const union ofp_action *actions, size_t n_actions, + const struct flow *flow, int max_ports) { - const struct ofp_action_enqueue *oae; - uint16_t port; - int error; + const union ofp_action *a; + size_t left; - error = check_action_exact_len(a, len, 16); - if (error) { - return error; - } + OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) { + uint16_t port; + int error; + int code; - oae = (const struct ofp_action_enqueue *) a; - port = ntohs(oae->port); - if (port < max_ports || port == OFPP_IN_PORT) { - return 0; - } - VLOG_WARN_RL(&bad_ofmsg_rl, "unknown enqueue port %x", port); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); -} + code = ofputil_decode_action(a); + if (code < 0) { + char *msg; -static int -check_nicira_action(const union ofp_action *a, unsigned int len, - const struct flow *flow) -{ - const struct nx_action_header *nah; - int subtype; - int error; + error = -code; + msg = ofputil_error_to_string(error); + VLOG_WARN_RL(&bad_ofmsg_rl, + "action decoding error at offset %td (%s)", + (a - actions) * sizeof *a, msg); + free(msg); - if (len < 16) { - VLOG_WARN_RL(&bad_ofmsg_rl, - "Nicira vendor action only %u bytes", len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - nah = (const struct nx_action_header *) a; + return error; + } - subtype = ntohs(nah->subtype); - if (subtype > TYPE_MAXIMUM(enum nx_action_subtype)) { - /* This is necessary because enum nx_action_subtype may be an - * 8-bit type, so the cast below throws away the top 8 bits. */ - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); - } + error = 0; + switch ((enum ofputil_action_code) code) { + case OFPUTIL_OFPAT_OUTPUT: + error = ofputil_check_output_port(ntohs(a->output.port), + max_ports); + break; - switch ((enum nx_action_subtype) subtype) { - case NXAST_RESUBMIT: - case NXAST_SET_TUNNEL: - case NXAST_SET_QUEUE: - case NXAST_POP_QUEUE: - return check_nx_action_exact_len(nah, len, 16); + case OFPUTIL_OFPAT_SET_VLAN_VID: + if (a->vlan_vid.vlan_vid & ~htons(0xfff)) { + error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + break; - case NXAST_REG_MOVE: - error = check_nx_action_exact_len(nah, len, - sizeof(struct nx_action_reg_move)); - if (error) { - return error; - } - return nxm_check_reg_move((const struct nx_action_reg_move *) a, flow); + case OFPUTIL_OFPAT_SET_VLAN_PCP: + if (a->vlan_pcp.vlan_pcp & ~7) { + error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + break; - case NXAST_REG_LOAD: - error = check_nx_action_exact_len(nah, len, - sizeof(struct nx_action_reg_load)); - if (error) { - return error; - } - return nxm_check_reg_load((const struct nx_action_reg_load *) a, flow); + case OFPUTIL_OFPAT_ENQUEUE: + port = ntohs(((const struct ofp_action_enqueue *) a)->port); + if (port >= max_ports && port != OFPP_IN_PORT) { + error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + } + break; - case NXAST_NOTE: - return 0; + case OFPUTIL_NXAST_REG_MOVE: + error = nxm_check_reg_move((const struct nx_action_reg_move *) a, + flow); + break; - case NXAST_SET_TUNNEL64: - return check_nx_action_exact_len( - nah, len, sizeof(struct nx_action_set_tunnel64)); + case OFPUTIL_NXAST_REG_LOAD: + error = nxm_check_reg_load((const struct nx_action_reg_load *) a, + flow); + break; - case NXAST_MULTIPATH: - error = check_nx_action_exact_len( - nah, len, sizeof(struct nx_action_multipath)); - if (error) { - return error; + 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_OFPAT_STRIP_VLAN: + case OFPUTIL_OFPAT_SET_NW_SRC: + case OFPUTIL_OFPAT_SET_NW_DST: + case OFPUTIL_OFPAT_SET_NW_TOS: + case OFPUTIL_OFPAT_SET_TP_SRC: + case OFPUTIL_OFPAT_SET_TP_DST: + case OFPUTIL_OFPAT_SET_DL_SRC: + case OFPUTIL_OFPAT_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: + break; } - return multipath_check((const struct nx_action_multipath *) a); - case NXAST_AUTOPATH: - error = check_nx_action_exact_len( - nah, len, sizeof(struct nx_action_autopath)); if (error) { + char *msg = ofputil_error_to_string(error); + VLOG_WARN_RL(&bad_ofmsg_rl, "bad action at offset %td (%s)", + (a - actions) * sizeof *a, msg); + free(msg); return error; } - return autopath_check((const struct nx_action_autopath *) a); - - case NXAST_SNAT__OBSOLETE: - case NXAST_DROP_SPOOFED_ARP__OBSOLETE: - default: - VLOG_WARN_RL(&bad_ofmsg_rl, - "unknown Nicira vendor action subtype %d", subtype); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); } + if (left) { + VLOG_WARN_RL(&bad_ofmsg_rl, "bad action format at offset %zu", + (n_actions - left) * sizeof *a); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + return 0; } -static int -check_action(const union ofp_action *a, unsigned int len, - const struct flow *flow, int max_ports) -{ - enum ofp_action_type type = ntohs(a->type); - int error; +struct ofputil_ofpat_action { + enum ofputil_action_code code; + unsigned int len; +}; - switch (type) { - case OFPAT_OUTPUT: - error = check_action_exact_len(a, len, 8); - if (error) { - return error; - } - return check_output_port(ntohs(a->output.port), max_ports); +static const struct ofputil_ofpat_action ofpat_actions[] = { + { OFPUTIL_OFPAT_OUTPUT, 8 }, + { OFPUTIL_OFPAT_SET_VLAN_VID, 8 }, + { OFPUTIL_OFPAT_SET_VLAN_PCP, 8 }, + { OFPUTIL_OFPAT_STRIP_VLAN, 8 }, + { OFPUTIL_OFPAT_SET_DL_SRC, 16 }, + { OFPUTIL_OFPAT_SET_DL_DST, 16 }, + { OFPUTIL_OFPAT_SET_NW_SRC, 8 }, + { OFPUTIL_OFPAT_SET_NW_DST, 8 }, + { OFPUTIL_OFPAT_SET_NW_TOS, 8 }, + { OFPUTIL_OFPAT_SET_TP_SRC, 8 }, + { OFPUTIL_OFPAT_SET_TP_DST, 8 }, + { OFPUTIL_OFPAT_ENQUEUE, 16 }, +}; - case OFPAT_SET_VLAN_VID: - error = check_action_exact_len(a, len, 8); - if (error) { - return error; - } - if (a->vlan_vid.vlan_vid & ~htons(0xfff)) { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); - } - return 0; +struct ofputil_nxast_action { + enum ofputil_action_code code; + unsigned int min_len; + unsigned int max_len; +}; - case OFPAT_SET_VLAN_PCP: - error = check_action_exact_len(a, len, 8); - if (error) { - return error; - } - if (a->vlan_pcp.vlan_pcp & ~7) { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); - } - return 0; +static const struct ofputil_nxast_action nxast_actions[] = { + { 0, UINT_MAX, UINT_MAX }, /* NXAST_SNAT__OBSOLETE */ + { OFPUTIL_NXAST_RESUBMIT, 16, 16 }, + { OFPUTIL_NXAST_SET_TUNNEL, 16, 16 }, + { 0, UINT_MAX, UINT_MAX }, /* NXAST_DROP_SPOOFED_ARP__OBSOLETE */ + { OFPUTIL_NXAST_SET_QUEUE, 16, 16 }, + { OFPUTIL_NXAST_POP_QUEUE, 16, 16 }, + { OFPUTIL_NXAST_REG_MOVE, 24, 24 }, + { OFPUTIL_NXAST_REG_LOAD, 24, 24 }, + { OFPUTIL_NXAST_NOTE, 16, UINT_MAX }, + { OFPUTIL_NXAST_SET_TUNNEL64, 24, 24 }, + { OFPUTIL_NXAST_MULTIPATH, 32, 32 }, + { OFPUTIL_NXAST_AUTOPATH, 24, 24 }, + { OFPUTIL_NXAST_BUNDLE, 32, UINT_MAX }, + { OFPUTIL_NXAST_BUNDLE_LOAD, 32, UINT_MAX }, +}; - case OFPAT_STRIP_VLAN: - case OFPAT_SET_NW_SRC: - case OFPAT_SET_NW_DST: - case OFPAT_SET_NW_TOS: - case OFPAT_SET_TP_SRC: - case OFPAT_SET_TP_DST: - return check_action_exact_len(a, len, 8); +static int +ofputil_decode_ofpat_action(const union ofp_action *a) +{ + int type = ntohs(a->type); - case OFPAT_SET_DL_SRC: - case OFPAT_SET_DL_DST: - return check_action_exact_len(a, len, 16); + if (type < ARRAY_SIZE(ofpat_actions)) { + const struct ofputil_ofpat_action *ooa = &ofpat_actions[type]; + unsigned int len = ntohs(a->header.len); - case OFPAT_VENDOR: - return (a->vendor.vendor == htonl(NX_VENDOR_ID) - ? check_nicira_action(a, len, flow) - : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR)); + return (len == ooa->len + ? ooa->code + : -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN)); + } else { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + } +} - case OFPAT_ENQUEUE: - return check_enqueue_action(a, len, max_ports); +static int +ofputil_decode_nxast_action(const union ofp_action *a) +{ + unsigned int len = ntohs(a->header.len); - default: - VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %d", (int) type); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + if (len < sizeof(struct nx_action_header)) { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } else { + const struct nx_action_header *nah = (const void *) a; + int subtype = ntohs(nah->subtype); + + if (subtype <= ARRAY_SIZE(nxast_actions)) { + const struct ofputil_nxast_action *ona = &nxast_actions[subtype]; + if (len >= ona->min_len && len <= ona->max_len) { + return ona->code; + } else if (ona->min_len == UINT_MAX) { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + } else { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + } else { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + } } } +/* Parses 'a' to determine its type. Returns a nonnegative OFPUTIL_OFPAT_* or + * OFPUTIL_NXAST_* constant if successful, otherwise a negative OpenFlow error + * code (as returned by ofp_mkerr()). + * + * 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 -validate_actions(const union ofp_action *actions, size_t n_actions, - const struct flow *flow, int max_ports) +ofputil_decode_action(const union ofp_action *a) { - size_t i; - - for (i = 0; i < n_actions; ) { - const union ofp_action *a = &actions[i]; - unsigned int len = ntohs(a->header.len); - unsigned int n_slots = len / OFP_ACTION_ALIGN; - unsigned int slots_left = &actions[n_actions] - a; - int error; + if (a->type != htons(OFPAT_VENDOR)) { + return ofputil_decode_ofpat_action(a); + } else if (a->vendor.vendor == htonl(NX_VENDOR_ID)) { + return ofputil_decode_nxast_action(a); + } else { + return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR); + } +} - if (n_slots > slots_left) { - VLOG_WARN_RL(&bad_ofmsg_rl, - "action requires %u slots but only %u remain", - n_slots, slots_left); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (!len) { - VLOG_WARN_RL(&bad_ofmsg_rl, "action has invalid length 0"); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (len % OFP_ACTION_ALIGN) { - VLOG_WARN_RL(&bad_ofmsg_rl, "action length %u is not a multiple " - "of %d", len, OFP_ACTION_ALIGN); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } +/* Parses 'a' and returns its type as an OFPUTIL_OFPAT_* 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) +{ + if (a->type != htons(OFPAT_VENDOR)) { + return ofpat_actions[ntohs(a->type)].code; + } else { + const struct nx_action_header *nah = (const void *) a; - error = check_action(a, len, flow, max_ports); - if (error) { - return error; - } - i += n_slots; + return nxast_actions[ntohs(nah->subtype)].code; } - return 0; } /* Returns true if 'action' outputs to 'port', false otherwise. */ @@ -2206,30 +2215,6 @@ action_outputs_to_port(const union ofp_action *action, ovs_be16 port) } } -/* The set of actions must either come from a trusted source or have been - * previously validated with validate_actions(). */ -const union ofp_action * -actions_first(struct actions_iterator *iter, - const union ofp_action *oa, size_t n_actions) -{ - iter->pos = oa; - iter->end = oa + n_actions; - return actions_next(iter); -} - -const union ofp_action * -actions_next(struct actions_iterator *iter) -{ - if (iter->pos != iter->end) { - const union ofp_action *a = iter->pos; - unsigned int len = ntohs(a->header.len); - iter->pos += len / OFP_ACTION_ALIGN; - return a; - } else { - return NULL; - } -} - /* "Normalizes" the wildcards in 'rule'. That means: * * 1. If the type of level N is known, then only the valid fields for that