X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=a4b1f5fc61dcb8c3e761f13c28bd795eb14df23c;hb=3a48ace3e4799ce25099a8584372abe7a4d6d771;hp=00f9ce8bf124db73e5934522b9328a1880d0ad6a;hpb=38f2e36072c9065cae3d4fbab4a70e4f502706cd;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 00f9ce8b..a4b1f5fc 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" @@ -107,6 +108,8 @@ static const flow_wildcards_t WC_INVARIANTS = 0 void ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc) { + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 1); + /* Initialize most of rule->wc. */ flow_wildcards_init_catchall(wc); wc->wildcards = (OVS_FORCE flow_wildcards_t) ofpfw & WC_INVARIANTS; @@ -799,6 +802,8 @@ ofputil_min_flow_format(const struct cls_rule *rule) { const struct flow_wildcards *wc = &rule->wc; + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 1); + /* Only NXM supports separately wildcards the Ethernet multicast bit. */ if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) { return NXFF_NXM; @@ -865,8 +870,8 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id) * * Does not validate the flow_mod actions. */ int -ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh, - bool flow_mod_table_id) +ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, + const struct ofp_header *oh, bool flow_mod_table_id) { const struct ofputil_msg_type *type; uint16_t command; @@ -955,7 +960,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh, * 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is * enabled, false otherwise. */ struct ofpbuf * -ofputil_encode_flow_mod(const struct flow_mod *fm, +ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, enum nx_flow_format flow_format, bool flow_mod_table_id) { @@ -1009,7 +1014,7 @@ ofputil_encode_flow_mod(const struct flow_mod *fm, } static int -ofputil_decode_ofpst_flow_request(struct flow_stats_request *fsr, +ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh, bool aggregate) { @@ -1025,7 +1030,7 @@ ofputil_decode_ofpst_flow_request(struct flow_stats_request *fsr, } static int -ofputil_decode_nxst_flow_request(struct flow_stats_request *fsr, +ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh, bool aggregate) { @@ -1055,7 +1060,7 @@ ofputil_decode_nxst_flow_request(struct flow_stats_request *fsr, * request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0 if * successful, otherwise an OpenFlow error code. */ int -ofputil_decode_flow_stats_request(struct flow_stats_request *fsr, +ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh) { const struct ofputil_msg_type *type; @@ -1089,7 +1094,7 @@ ofputil_decode_flow_stats_request(struct flow_stats_request *fsr, * OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE request 'oh' according to * 'flow_format', and returns the message. */ struct ofpbuf * -ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr, +ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, enum nx_flow_format flow_format) { struct ofpbuf *msg; @@ -1878,7 +1883,7 @@ make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, opo->header.length = htons(size); opo->header.xid = htonl(0); opo->buffer_id = htonl(buffer_id); - opo->in_port = htons(in_port == ODPP_LOCAL ? OFPP_LOCAL : in_port); + opo->in_port = htons(in_port == OVSP_LOCAL ? OFPP_LOCAL : in_port); opo->actions_len = htons(actions_len); ofpbuf_put(out, actions, actions_len); if (packet) { @@ -1944,8 +1949,8 @@ make_echo_reply(const struct ofp_header *rq) /* 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: @@ -1965,6 +1970,31 @@ check_output_port(uint16_t port, int max_ports) } } +static int +check_resubmit_table(const struct nx_action_resubmit *nar) +{ + if (nar->pad[0] || nar->pad[1] || nar->pad[2]) { + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + return 0; +} + +static int +check_output_reg(const struct nx_action_output_reg *naor, + const struct flow *flow) +{ + size_t i; + + for (i = 0; i < sizeof naor->zero; i++) { + if (naor->zero[i]) { + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + } + + return nxm_src_check(naor->src, nxm_decode_ofs(naor->ofs_nbits), + nxm_decode_n_bits(naor->ofs_nbits), flow); +} + int validate_actions(const union ofp_action *actions, size_t n_actions, const struct flow *flow, int max_ports) @@ -1994,7 +2024,8 @@ validate_actions(const union ofp_action *actions, size_t n_actions, error = 0; switch ((enum ofputil_action_code) code) { case OFPUTIL_OFPAT_OUTPUT: - error = check_output_port(ntohs(a->output.port), max_ports); + error = ofputil_check_output_port(ntohs(a->output.port), + max_ports); break; case OFPUTIL_OFPAT_SET_VLAN_VID: @@ -2027,11 +2058,29 @@ validate_actions(const union ofp_action *actions, size_t n_actions, break; case OFPUTIL_NXAST_MULTIPATH: - error = multipath_check((const struct nx_action_multipath *) a); + error = multipath_check((const struct nx_action_multipath *) a, + flow); break; case OFPUTIL_NXAST_AUTOPATH: - error = autopath_check((const struct nx_action_autopath *) a); + 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_OFPAT_STRIP_VLAN: @@ -2067,87 +2116,88 @@ validate_actions(const union ofp_action *actions, size_t n_actions, return 0; } -struct ofputil_ofpat_action { - enum ofputil_action_code code; - unsigned int len; -}; - -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 }, -}; - -struct ofputil_nxast_action { - enum ofputil_action_code code; +struct ofputil_action { + int code; unsigned int min_len; unsigned int max_len; }; -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 }, -}; +static const struct ofputil_action action_bad_type + = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE), 0, UINT_MAX }; +static const struct ofputil_action action_bad_len + = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_LEN), 0, UINT_MAX }; +static const struct ofputil_action action_bad_vendor + = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR), 0, UINT_MAX }; -static int +static const struct ofputil_action * ofputil_decode_ofpat_action(const union ofp_action *a) { - int type = ntohs(a->type); - - if (type < ARRAY_SIZE(ofpat_actions)) { - const struct ofputil_ofpat_action *ooa = &ofpat_actions[type]; - unsigned int len = ntohs(a->header.len); + enum ofp_action_type type = ntohs(a->type); - return (len == ooa->len - ? ooa->code - : -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN)); - } else { - return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + switch (type) { +#define OFPAT_ACTION(ENUM, TYPE) \ + case ENUM: { \ + static const struct ofputil_action action = { \ + OFPUTIL_##ENUM, sizeof(TYPE), sizeof(TYPE) \ + }; \ + return &action; \ + } + OFPAT_ACTION(OFPAT_OUTPUT, struct ofp_action_output); + OFPAT_ACTION(OFPAT_SET_VLAN_VID, struct ofp_action_vlan_vid); + OFPAT_ACTION(OFPAT_SET_VLAN_PCP, struct ofp_action_vlan_pcp); + OFPAT_ACTION(OFPAT_STRIP_VLAN, struct ofp_action_header); + OFPAT_ACTION(OFPAT_SET_DL_SRC, struct ofp_action_dl_addr); + OFPAT_ACTION(OFPAT_SET_DL_DST, struct ofp_action_dl_addr); + OFPAT_ACTION(OFPAT_SET_NW_SRC, struct ofp_action_nw_addr); + OFPAT_ACTION(OFPAT_SET_NW_DST, struct ofp_action_nw_addr); + OFPAT_ACTION(OFPAT_SET_NW_TOS, struct ofp_action_nw_tos); + OFPAT_ACTION(OFPAT_SET_TP_SRC, struct ofp_action_tp_port); + OFPAT_ACTION(OFPAT_SET_TP_DST, struct ofp_action_tp_port); + OFPAT_ACTION(OFPAT_ENQUEUE, struct ofp_action_enqueue); +#undef OFPAT_ACTION + + case OFPAT_VENDOR: + default: + return &action_bad_type; } } -static int +static const struct ofputil_action * ofputil_decode_nxast_action(const union ofp_action *a) { - unsigned int len = ntohs(a->header.len); - - 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); + 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, TYPE, EXTENSIBLE) \ + case ENUM: { \ + static const struct ofputil_action action = { \ + OFPUTIL_##ENUM, \ + sizeof(TYPE), \ + EXTENSIBLE ? UINT_MAX : sizeof(TYPE) \ + }; \ + return &action; \ } + NXAST_ACTION(NXAST_RESUBMIT, struct nx_action_resubmit, false); + NXAST_ACTION(NXAST_SET_TUNNEL, struct nx_action_set_tunnel, false); + NXAST_ACTION(NXAST_SET_QUEUE, struct nx_action_set_queue, false); + NXAST_ACTION(NXAST_POP_QUEUE, struct nx_action_pop_queue, false); + NXAST_ACTION(NXAST_REG_MOVE, struct nx_action_reg_move, false); + NXAST_ACTION(NXAST_REG_LOAD, struct nx_action_reg_load, false); + NXAST_ACTION(NXAST_NOTE, struct nx_action_note, true); + NXAST_ACTION(NXAST_SET_TUNNEL64, struct nx_action_set_tunnel64, false); + NXAST_ACTION(NXAST_MULTIPATH, struct nx_action_multipath, false); + NXAST_ACTION(NXAST_AUTOPATH, struct nx_action_autopath, false); + NXAST_ACTION(NXAST_BUNDLE, struct nx_action_bundle, true); + NXAST_ACTION(NXAST_BUNDLE_LOAD, struct nx_action_bundle, true); + NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit, false); + NXAST_ACTION(NXAST_OUTPUT_REG, struct nx_action_output_reg, false); +#undef NXAST_ACTION + + case NXAST_SNAT__OBSOLETE: + case NXAST_DROP_SPOOFED_ARP__OBSOLETE: + default: + return &action_bad_type; } } @@ -2164,13 +2214,28 @@ ofputil_decode_nxast_action(const union ofp_action *a) 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(OFPAT_VENDOR)) { - return ofputil_decode_ofpat_action(a); - } else if (a->vendor.vendor == htonl(NX_VENDOR_ID)) { - return ofputil_decode_nxast_action(a); + action = ofputil_decode_ofpat_action(a); } else { - return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR); + switch (ntohl(a->vendor.vendor)) { + case NX_VENDOR_ID: + if (len < sizeof(struct nx_action_header)) { + return -ofp_mkerr(OFPET_BAD_ACTION, 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 + : -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN)); } /* Parses 'a' and returns its type as an OFPUTIL_OFPAT_* or OFPUTIL_NXAST_* @@ -2180,13 +2245,15 @@ ofputil_decode_action(const union ofp_action *a) enum ofputil_action_code ofputil_decode_action_unsafe(const union ofp_action *a) { + const struct ofputil_action *action; + if (a->type != htons(OFPAT_VENDOR)) { - return ofpat_actions[ntohs(a->type)].code; + action = ofputil_decode_ofpat_action(a); } else { - const struct nx_action_header *nah = (const void *) a; - - return nxast_actions[ntohs(nah->subtype)].code; + action = ofputil_decode_nxast_action(a); } + + return action->code; } /* Returns true if 'action' outputs to 'port', false otherwise. */