X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=9dc5b2a5013b4a8ec672031fe6e482c2365504f6;hb=a23aab1fc2f66b63ba9b7e4b9c9a8f6d58c367d0;hp=94682eb479433e0c058ad177bf353ca7d17908e1;hpb=4d326addd3cb44e9608f7d1ef527adf4be26edec;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 94682eb4..9dc5b2a5 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -18,15 +18,15 @@ #include "ofp-print.h" #include #include +#include "byte-order.h" #include "ofp-util.h" #include "ofpbuf.h" #include "packets.h" #include "random.h" -#include "xtoxll.h" - -#define THIS_MODULE VLM_ofp_util #include "vlog.h" +VLOG_DEFINE_THIS_MODULE(ofp_util); + /* Rate limit for OpenFlow message parse errors. These always indicate a bug * in the peer and so there's not much point in showing a lot of them. */ static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -125,14 +125,14 @@ put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, /* Updates the 'length' field of the OpenFlow message in 'buffer' to * 'buffer->size'. */ void -update_openflow_length(struct ofpbuf *buffer) +update_openflow_length(struct ofpbuf *buffer) { struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - oh->length = htons(buffer->size); + oh->length = htons(buffer->size); } struct ofpbuf * -make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len) +make_flow_mod(uint16_t command, const struct flow *flow, size_t actions_len) { struct ofp_flow_mod *ofm; size_t size = sizeof *ofm + actions_len; @@ -161,7 +161,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len) } struct ofpbuf * -make_add_flow(const flow_t *flow, uint32_t buffer_id, +make_add_flow(const struct flow *flow, uint32_t buffer_id, uint16_t idle_timeout, size_t actions_len) { struct ofpbuf *out = make_flow_mod(OFPFC_ADD, flow, actions_len); @@ -173,7 +173,7 @@ make_add_flow(const flow_t *flow, uint32_t buffer_id, } struct ofpbuf * -make_del_flow(const flow_t *flow) +make_del_flow(const struct flow *flow) { struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, flow, 0); struct ofp_flow_mod *ofm = out->data; @@ -182,18 +182,23 @@ make_del_flow(const flow_t *flow) } struct ofpbuf * -make_add_simple_flow(const flow_t *flow, +make_add_simple_flow(const struct flow *flow, uint32_t buffer_id, uint16_t out_port, uint16_t idle_timeout) { - struct ofp_action_output *oao; - struct ofpbuf *buffer = make_add_flow(flow, buffer_id, idle_timeout, - sizeof *oao); - oao = ofpbuf_put_zeros(buffer, sizeof *oao); - oao->type = htons(OFPAT_OUTPUT); - oao->len = htons(sizeof *oao); - oao->port = htons(out_port); - return buffer; + if (out_port != OFPP_NONE) { + struct ofp_action_output *oao; + struct ofpbuf *buffer; + + buffer = make_add_flow(flow, buffer_id, idle_timeout, sizeof *oao); + oao = ofpbuf_put_zeros(buffer, sizeof *oao); + oao->type = htons(OFPAT_OUTPUT); + oao->len = htons(sizeof *oao); + oao->port = htons(out_port); + return buffer; + } else { + return make_add_flow(flow, buffer_id, idle_timeout, 0); + } } struct ofpbuf * @@ -259,12 +264,16 @@ struct ofpbuf * make_buffered_packet_out(uint32_t buffer_id, uint16_t in_port, uint16_t out_port) { - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htons(out_port); - return make_packet_out(NULL, buffer_id, in_port, - (struct ofp_action_header *) &action, 1); + if (out_port != OFPP_NONE) { + struct ofp_action_output action; + action.type = htons(OFPAT_OUTPUT); + action.len = htons(sizeof action); + action.port = htons(out_port); + return make_packet_out(NULL, buffer_id, in_port, + (struct ofp_action_header *) &action, 1); + } else { + return make_packet_out(NULL, buffer_id, in_port, NULL, 0); + } } /* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */ @@ -294,7 +303,7 @@ make_echo_reply(const struct ofp_header *rq) } static int -check_message_type(uint8_t got_type, uint8_t want_type) +check_message_type(uint8_t got_type, uint8_t want_type) { if (got_type != want_type) { char *want_type_name = ofp_message_type_to_string(want_type); @@ -555,6 +564,9 @@ check_nicira_action(const union ofp_action *a, unsigned int len) switch (ntohs(nah->subtype)) { case NXAST_RESUBMIT: case NXAST_SET_TUNNEL: + case NXAST_DROP_SPOOFED_ARP: + case NXAST_SET_QUEUE: + case NXAST_POP_QUEUE: return check_action_exact_len(a, len, 16); default: return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); @@ -575,7 +587,25 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports) return check_output_port(ntohs(a->output.port), max_ports); 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; + case OFPAT_SET_VLAN_PCP: + error = check_action_exact_len(a, len, 8); + if (error) { + return error; + } + if (a->vlan_vid.vlan_vid & ~7) { + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + } + return 0; + case OFPAT_STRIP_VLAN: case OFPAT_SET_NW_SRC: case OFPAT_SET_NW_DST: @@ -607,9 +637,10 @@ int validate_actions(const union ofp_action *actions, size_t n_actions, int max_ports) { - const union ofp_action *a; + size_t i; - for (a = actions; a < &actions[n_actions]; ) { + 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 / ACTION_ALIGNMENT; unsigned int slots_left = &actions[n_actions] - a; @@ -633,7 +664,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions, if (error) { return error; } - a += n_slots; + i += n_slots; } return 0; } @@ -667,7 +698,7 @@ actions_first(struct actions_iterator *iter, const union ofp_action * actions_next(struct actions_iterator *iter) { - if (iter->pos < iter->end) { + if (iter->pos != iter->end) { const union ofp_action *a = iter->pos; unsigned int len = ntohs(a->header.len); iter->pos += len / ACTION_ALIGNMENT; @@ -680,7 +711,8 @@ actions_next(struct actions_iterator *iter) void normalize_match(struct ofp_match *m) { - enum { OFPFW_NW = OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO }; + enum { OFPFW_NW = (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO + | OFPFW_NW_TOS) }; enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST }; uint32_t wc; @@ -754,3 +786,130 @@ normalize_match(struct ofp_match *m) m->wildcards = htonl(wc); } +/* Returns a string that describes 'match' in a very literal way, without + * interpreting its contents except in a very basic fashion. The returned + * string is intended to be fixed-length, so that it is easy to see differences + * between two such strings if one is put above another. This is useful for + * describing changes made by normalize_match(). + * + * The caller must free the returned string (with free()). */ +char * +ofp_match_to_literal_string(const struct ofp_match *match) +{ + return xasprintf("wildcards=%#10"PRIx32" " + " in_port=%5"PRId16" " + " dl_src="ETH_ADDR_FMT" " + " dl_dst="ETH_ADDR_FMT" " + " dl_vlan=%5"PRId16" " + " dl_vlan_pcp=%3"PRId8" " + " dl_type=%#6"PRIx16" " + " nw_tos=%#4"PRIx8" " + " nw_proto=%#4"PRIx16" " + " nw_src=%#10"PRIx32" " + " nw_dst=%#10"PRIx32" " + " tp_src=%5"PRId16" " + " tp_dst=%5"PRId16, + ntohl(match->wildcards), + ntohs(match->in_port), + ETH_ADDR_ARGS(match->dl_src), + ETH_ADDR_ARGS(match->dl_dst), + ntohs(match->dl_vlan), + match->dl_vlan_pcp, + ntohs(match->dl_type), + match->nw_tos, + match->nw_proto, + ntohl(match->nw_src), + ntohl(match->nw_dst), + ntohs(match->tp_src), + ntohs(match->tp_dst)); +} + +static uint32_t +vendor_code_to_id(uint8_t code) +{ + switch (code) { +#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case NAME: return VENDOR_ID; + default: + return UINT32_MAX; + } +} + +/* Creates and returns an OpenFlow message of type OFPT_ERROR with the error + * information taken from 'error', whose encoding must be as described in the + * large comment in ofp-util.h. If 'oh' is nonnull, then the error will use + * oh->xid as its transaction ID, and it will include up to the first 64 bytes + * of 'oh'. + * + * Returns NULL if 'error' is not an OpenFlow error code. */ +struct ofpbuf * +make_ofp_error_msg(int error, const struct ofp_header *oh) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + + struct ofpbuf *buf; + const void *data; + size_t len; + uint8_t vendor; + uint16_t type; + uint16_t code; + uint32_t xid; + + if (!is_ofp_error(error)) { + /* We format 'error' with strerror() here since it seems likely to be + * a system errno value. */ + VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)", + error, strerror(error)); + return NULL; + } + + if (oh) { + xid = oh->xid; + data = oh; + len = ntohs(oh->length); + if (len > 64) { + len = 64; + } + } else { + xid = 0; + data = NULL; + len = 0; + } + + vendor = get_ofp_err_vendor(error); + type = get_ofp_err_type(error); + code = get_ofp_err_code(error); + if (vendor == OFPUTIL_VENDOR_OPENFLOW) { + struct ofp_error_msg *oem; + + oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR, xid, &buf); + oem->type = htons(type); + oem->code = htons(code); + } else { + struct ofp_error_msg *oem; + struct nx_vendor_error *ove; + uint32_t vendor_id; + + vendor_id = vendor_code_to_id(vendor); + if (vendor_id == UINT32_MAX) { + VLOG_WARN_RL(&rl, "error %x contains invalid vendor code %d", + error, vendor); + return NULL; + } + + oem = make_openflow_xid(len + sizeof *oem + sizeof *ove, + OFPT_ERROR, xid, &buf); + oem->type = htons(NXET_VENDOR); + oem->code = htons(NXVC_VENDOR_ERROR); + + ove = ofpbuf_put_uninit(buf, sizeof *ove); + ove->vendor = htonl(vendor_id); + ove->type = htons(type); + ove->code = htons(code); + } + + if (len) { + ofpbuf_put(buf, data, len); + } + + return buf; +}