X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnx-match.c;h=15143f17c84571ddd24e190c47db94a303bfdccf;hb=f47ea0215f0fc2898815c903276d9ec8afd0306e;hp=a91d56b9aa4db2a64e4de60be686c9c73c27a2c8;hpb=72333065758f8d7de2de0b047da781ee444904d1;p=sliver-openvswitch.git diff --git a/lib/nx-match.c b/lib/nx-match.c index a91d56b9a..15143f17c 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -183,7 +183,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, if (NXM_HASMASK(header)) { memcpy(cookie_mask, p + 4 + width, width); } else { - *cookie_mask = htonll(UINT64_MAX); + *cookie_mask = OVS_BE64_MAX; } error = 0; } @@ -280,7 +280,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) strict, match, NULL, NULL); } -/* Parses the oxm formatted match description preceeded by a struct ofp11_match +/* Parses the oxm formatted match description preceded by a struct ofp11_match * in 'b' with length 'match_len'. Stores the result in 'match'. * * Fails with an error when encountering unknown OXM headers. @@ -361,7 +361,7 @@ nxm_put_16m(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask) case 0: break; - case CONSTANT_HTONS(UINT16_MAX): + case OVS_BE16_MAX: nxm_put_16(b, header, value); break; @@ -393,7 +393,7 @@ nxm_put_32m(struct ofpbuf *b, uint32_t header, ovs_be32 value, ovs_be32 mask) case 0: break; - case CONSTANT_HTONL(UINT32_MAX): + case OVS_BE32_MAX: nxm_put_32(b, header, value); break; @@ -425,7 +425,7 @@ nxm_put_64m(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask) case 0: break; - case CONSTANT_HTONLL(UINT64_MAX): + case OVS_BE64_MAX: nxm_put_64(b, header, value); break; @@ -535,6 +535,11 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, flow->tp_src, match->wc.masks.tp_src); nxm_put_16m(b, oxm ? OXM_OF_UDP_DST : NXM_OF_UDP_DST, flow->tp_dst, match->wc.masks.tp_dst); + } else if (flow->nw_proto == IPPROTO_SCTP) { + nxm_put_16m(b, OXM_OF_SCTP_SRC, flow->tp_src, + match->wc.masks.tp_src); + nxm_put_16m(b, OXM_OF_SCTP_DST, flow->tp_dst, + match->wc.masks.tp_dst); } else if (flow->nw_proto == icmp_proto) { if (match->wc.masks.tp_src) { nxm_put_8(b, icmp_type, ntohs(flow->tp_src)); @@ -565,15 +570,15 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match, int match_len; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 21); /* Metadata. */ - if (match->wc.masks.in_port) { - uint16_t in_port = flow->in_port; + if (match->wc.masks.in_port.ofp_port) { + ofp_port_t in_port = flow->in_port.ofp_port; if (oxm) { nxm_put_32(b, OXM_OF_IN_PORT, ofputil_port_to_ofp11(in_port)); } else { - nxm_put_16(b, NXM_OF_IN_PORT, htons(in_port)); + nxm_put_16(b, NXM_OF_IN_PORT, htons(ofp_to_u16(in_port))); } } @@ -693,6 +698,10 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match, htonl(flow->regs[i]), htonl(match->wc.masks.regs[i])); } + /* Mark. */ + nxm_put_32m(b, NXM_NX_PKT_MARK, htonl(flow->pkt_mark), + htonl(match->wc.masks.pkt_mark)); + /* OpenFlow 1.1+ Metadata. */ nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, match->wc.masks.metadata); @@ -744,7 +753,7 @@ oxm_put_match(struct ofpbuf *b, const struct match *match) match_len = nx_put_raw(b, true, match, cookie, cookie_mask) + sizeof *omh; ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len); - omh = (struct ofp11_match_header *)((char *)b->data + start_len); + omh = ofpbuf_at(b, start_len, sizeof *omh); omh->type = htons(OFPMT_OXM); omh->length = htons(match_len); @@ -807,9 +816,9 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len) } char * -oxm_match_to_string(const uint8_t *p, unsigned int match_len) +oxm_match_to_string(const struct ofpbuf *p, unsigned int match_len) { - const struct ofp11_match_header *omh = (struct ofp11_match_header *)p; + const struct ofp11_match_header *omh = p->data; uint16_t match_len_; struct ds s; @@ -837,7 +846,8 @@ oxm_match_to_string(const uint8_t *p, unsigned int match_len) goto err; } - return nx_match_to_string(p + sizeof *omh, match_len - sizeof *omh); + return nx_match_to_string(ofpbuf_at(p, sizeof *omh, 0), + match_len - sizeof *omh); err: return ds_steal_cstr(&s); @@ -997,57 +1007,74 @@ oxm_match_from_string(const char *s, struct ofpbuf *b) match_len = nx_match_from_string_raw(s, b) + sizeof *omh; ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len); - omh = (struct ofp11_match_header *)((char *)b->data + start_len); + omh = ofpbuf_at(b, start_len, sizeof *omh); omh->type = htons(OFPMT_OXM); omh->length = htons(match_len); return match_len; } -void +/* Parses 's' as a "move" action, in the form described in ovs-ofctl(8), into + * '*move'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * WARN_UNUSED_RESULT nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s) { const char *full_s = s; + char *error; - s = mf_parse_subfield(&move->src, s); + error = mf_parse_subfield__(&move->src, &s); + if (error) { + return error; + } if (strncmp(s, "->", 2)) { - ovs_fatal(0, "%s: missing `->' following source", full_s); + return xasprintf("%s: missing `->' following source", full_s); } s += 2; - s = mf_parse_subfield(&move->dst, s); - if (*s != '\0') { - ovs_fatal(0, "%s: trailing garbage following destination", full_s); + error = mf_parse_subfield(&move->dst, s); + if (error) { + return error; } if (move->src.n_bits != move->dst.n_bits) { - ovs_fatal(0, "%s: source field is %d bits wide but destination is " - "%d bits wide", full_s, - move->src.n_bits, move->dst.n_bits); + return xasprintf("%s: source field is %d bits wide but destination is " + "%d bits wide", full_s, + move->src.n_bits, move->dst.n_bits); } + return NULL; } -void +/* Parses 's' as a "load" action, in the form described in ovs-ofctl(8), into + * '*load'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * WARN_UNUSED_RESULT nxm_parse_reg_load(struct ofpact_reg_load *load, const char *s) { const char *full_s = s; uint64_t value = strtoull(s, (char **) &s, 0); + char *error; if (strncmp(s, "->", 2)) { - ovs_fatal(0, "%s: missing `->' following value", full_s); + return xasprintf("%s: missing `->' following value", full_s); } s += 2; - s = mf_parse_subfield(&load->dst, s); - if (*s != '\0') { - ovs_fatal(0, "%s: trailing garbage following destination", full_s); + error = mf_parse_subfield(&load->dst, s); + if (error) { + return error; } if (load->dst.n_bits < 64 && (value >> load->dst.n_bits) != 0) { - ovs_fatal(0, "%s: value %"PRIu64" does not fit into %d bits", - full_s, value, load->dst.n_bits); + return xasprintf("%s: value %"PRIu64" does not fit into %d bits", + full_s, value, load->dst.n_bits); } load->subvalue.be64[0] = htonll(0); load->subvalue.be64[1] = htonll(value); + return NULL; } /* nxm_format_reg_move(), nxm_format_reg_load(). */ @@ -1146,19 +1173,19 @@ nxm_reg_load_from_openflow12_set_field( /* ofp12_action_set_field is padded to 64 bits by zero */ if (oasf_len != ROUND_UP(sizeof(*oasf) + oxm_length, 8)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; + return OFPERR_OFPBAC_BAD_SET_LEN; } if (!is_all_zeros((const uint8_t *)(oasf) + sizeof *oasf + oxm_length, oasf_len - oxm_length - sizeof *oasf)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } if (NXM_HASMASK(oxm_header)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; + return OFPERR_OFPBAC_BAD_SET_TYPE; } mf = mf_from_nxm_header(oxm_header); if (!mf) { - return OFPERR_OFPBAC_BAD_ARGUMENT; + return OFPERR_OFPBAC_BAD_SET_TYPE; } load = ofpact_put_REG_LOAD(ofpacts); ofpact_set_field_init(load, mf, oasf + 1); @@ -1279,11 +1306,14 @@ nxm_reg_load_to_nxast(const struct ofpact_reg_load *load, void nxm_execute_reg_move(const struct ofpact_reg_move *move, - struct flow *flow) + struct flow *flow, struct flow_wildcards *wc) { union mf_value src_value; union mf_value dst_value; + mf_mask_field_and_prereqs(move->dst.field, &wc->masks); + mf_mask_field_and_prereqs(move->src.field, &wc->masks); + mf_get_value(move->dst.field, flow, &dst_value); mf_get_value(move->src.field, flow, &src_value); bitwise_copy(&src_value, move->src.field->n_bytes, move->src.ofs, @@ -1293,18 +1323,47 @@ nxm_execute_reg_move(const struct ofpact_reg_move *move, } void -nxm_execute_reg_load(const struct ofpact_reg_load *load, struct flow *flow) -{ +nxm_execute_reg_load(const struct ofpact_reg_load *load, struct flow *flow, + struct flow_wildcards *wc) +{ + /* Since at the datapath interface we do not have set actions for + * individual fields, but larger sets of fields for a given protocol + * layer, the set action will in practice only ever apply to exactly + * matched flows for the given protocol layer. For example, if the + * reg_load changes the IP TTL, the corresponding datapath action will + * rewrite also the IP addresses and TOS byte. Since these other field + * values may not be explicitly set, they depend on the incoming flow field + * values, and are hence all of them are set in the wildcards masks, when + * the action is committed to the datapath. For the rare case, where the + * reg_load action does not actually change the value, and no other flow + * field values are set (or loaded), the datapath action is skipped, and + * no mask bits are set. Such a datapath flow should, however, be + * dependent on the specific field value, so the corresponding wildcard + * mask bits must be set, lest the datapath flow be applied to packets + * containing some other value in the field and the field value remain + * unchanged regardless of the incoming value. + * + * We set the masks here for the whole fields, and their prerequisities. + * Even if only the lower byte of a TCP destination port is set, + * we set the mask for the whole field, and also the ip_proto in the IP + * header, so that the kernel flow would not be applied on, e.g., a UDP + * packet, or any other IP protocol in addition to TCP packets. + */ + mf_mask_field_and_prereqs(load->dst.field, &wc->masks); mf_write_subfield_flow(&load->dst, &load->subvalue, flow); } void nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data, - struct flow *flow) + struct flow *flow, struct flow_wildcards *wc) { union mf_subvalue src_subvalue; + union mf_subvalue mask_value; ovs_be64 src_data_be = htonll(src_data); + memset(&mask_value, 0xff, sizeof mask_value); + mf_write_subfield_flow(dst, &mask_value, &wc->masks); + bitwise_copy(&src_data_be, sizeof src_data_be, 0, &src_subvalue, sizeof src_subvalue, 0, sizeof src_data_be * 8); @@ -1312,13 +1371,27 @@ nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data, } /* nxm_parse_stack_action, works for both push() and pop(). */ -void + +/* Parses 's' as a "push" or "pop" action, in the form described in + * ovs-ofctl(8), into '*stack_action'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * WARN_UNUSED_RESULT nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s) { - s = mf_parse_subfield(&stack_action->subfield, s); + char *error; + + error = mf_parse_subfield__(&stack_action->subfield, &s); + if (error) { + return error; + } + if (*s != '\0') { - ovs_fatal(0, "%s: trailing garbage following push or pop", s); + return xasprintf("%s: trailing garbage following push or pop", s); } + + return NULL; } void @@ -1428,17 +1501,23 @@ nx_stack_pop(struct ofpbuf *stack) void nxm_execute_stack_push(const struct ofpact_stack *push, - const struct flow *flow, struct ofpbuf *stack) + const struct flow *flow, struct flow_wildcards *wc, + struct ofpbuf *stack) { + union mf_subvalue mask_value; union mf_subvalue dst_value; + memset(&mask_value, 0xff, sizeof mask_value); + mf_write_subfield_flow(&push->subfield, &mask_value, &wc->masks); + mf_read_subfield(&push->subfield, flow, &dst_value); nx_stack_push(stack, &dst_value); } void nxm_execute_stack_pop(const struct ofpact_stack *pop, - struct flow *flow, struct ofpbuf *stack) + struct flow *flow, struct flow_wildcards *wc, + struct ofpbuf *stack) { union mf_subvalue *src_value; @@ -1446,6 +1525,10 @@ nxm_execute_stack_pop(const struct ofpact_stack *pop, /* Only pop if stack is not empty. Otherwise, give warning. */ if (src_value) { + union mf_subvalue mask_value; + + memset(&mask_value, 0xff, sizeof mask_value); + mf_write_subfield_flow(&pop->subfield, &mask_value, &wc->masks); mf_write_subfield_flow(&pop->subfield, src_value, flow); } else { if (!VLOG_DROP_WARN(&rl)) {