X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=5171900a77ecc5da665382f5df82b281f1b45d0e;hb=92467099ee05b930b060d34d05b81bb1322e6fbf;hp=d773a3fa9f0e8c5e73cf38f18948018ce89dde36;hpb=fa37b408eac875cbc0d7adbbb3f7a004371172da;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index d773a3fa..5171900a 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -22,9 +22,10 @@ #include "ofpbuf.h" #include "packets.h" #include "random.h" - -#define THIS_MODULE VLM_ofp_util #include "vlog.h" +#include "xtoxll.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. */ @@ -124,10 +125,10 @@ 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 * @@ -185,14 +186,19 @@ make_add_simple_flow(const flow_t *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 * @@ -258,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. */ @@ -293,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); @@ -489,8 +499,11 @@ check_action_exact_len(const union ofp_action *a, unsigned int 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_action_port(int port, int max_ports) +check_output_port(uint16_t port, int max_ports) { switch (port) { case OFPP_IN_PORT: @@ -503,7 +516,7 @@ check_action_port(int port, int max_ports) return 0; default: - if (port >= 0 && port < max_ports) { + if (port < max_ports) { return 0; } VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port); @@ -511,6 +524,31 @@ check_action_port(int port, int max_ports) } } +/* 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) +{ + const struct ofp_action_enqueue *oae; + uint16_t port; + int error; + + error = check_action_exact_len(a, len, 16); + if (error) { + return error; + } + + 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); +} + static int check_nicira_action(const union ofp_action *a, unsigned int len) { @@ -526,6 +564,7 @@ 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: return check_action_exact_len(a, len, 16); default: return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); @@ -539,8 +578,11 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports) switch (ntohs(a->type)) { case OFPAT_OUTPUT: - error = check_action_port(ntohs(a->output.port), max_ports); - return error ? error : check_action_exact_len(a, len, 8); + error = check_action_exact_len(a, len, 8); + if (error) { + return error; + } + return check_output_port(ntohs(a->output.port), max_ports); case OFPAT_SET_VLAN_VID: case OFPAT_SET_VLAN_PCP: @@ -561,6 +603,9 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports) ? check_nicira_action(a, len) : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR)); + case OFPAT_ENQUEUE: + return check_enqueue_action(a, len, max_ports); + default: VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16, ntohs(a->type)); @@ -603,6 +648,21 @@ validate_actions(const union ofp_action *actions, size_t n_actions, return 0; } +/* Returns true if 'action' outputs to 'port' (which must be in network byte + * order), false otherwise. */ +bool +action_outputs_to_port(const union ofp_action *action, uint16_t port) +{ + switch (ntohs(action->type)) { + case OFPAT_OUTPUT: + return action->output.port == port; + case OFPAT_ENQUEUE: + return ((const struct ofp_action_enqueue *) action)->port == port; + default: + return false; + } +} + /* The set of actions must either come from a trusted source or have been * previously validated with validate_actions(). */ const union ofp_action * @@ -641,7 +701,7 @@ normalize_match(struct ofp_match *m) /* Can't sensibly match on network or transport headers if the * data link type is unknown. */ wc |= OFPFW_NW | OFPFW_TP; - m->nw_src = m->nw_dst = m->nw_proto = 0; + m->nw_src = m->nw_dst = m->nw_proto = m->nw_tos = 0; m->tp_src = m->tp_dst = 0; } else if (m->dl_type == htons(ETH_TYPE_IP)) { if (wc & OFPFW_NW_PROTO) { @@ -672,6 +732,11 @@ normalize_match(struct ofp_match *m) if (wc & OFPFW_NW_DST_MASK) { m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT); } + if (wc & OFPFW_NW_TOS) { + m->nw_tos = 0; + } else { + m->nw_tos &= IP_DSCP_MASK; + } } else if (m->dl_type == htons(ETH_TYPE_ARP)) { if (wc & OFPFW_NW_PROTO) { m->nw_proto = 0; @@ -682,12 +747,12 @@ normalize_match(struct ofp_match *m) if (wc & OFPFW_NW_DST_MASK) { m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT); } - m->tp_src = m->tp_dst = 0; + m->tp_src = m->tp_dst = m->nw_tos = 0; } else { /* Network and transport layer fields will always be extracted as * zeros, so we can do an exact-match on those values. */ wc &= ~(OFPFW_NW | OFPFW_TP); - m->nw_proto = m->nw_src = m->nw_dst = 0; + m->nw_proto = m->nw_src = m->nw_dst = m->nw_tos = 0; m->tp_src = m->tp_dst = 0; } if (wc & OFPFW_DL_SRC) { @@ -699,3 +764,40 @@ 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)); +}