X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fnx-match.c;h=4999b1ac95d7672967928524f950a42b28f40e5e;hb=ca7e7bee86b4ee821d61b58bf15c89a9d8a3cb30;hp=1a6b89a8570d1194e53dd23fa7a10bfa78986d43;hpb=dc3eb9539f17f3b9a2ea9221a86221196b5c002e;p=cascardo%2Fovs.git diff --git a/lib/nx-match.c b/lib/nx-match.c index 1a6b89a85..4999b1ac9 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. + * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ #include "openflow/nicira-ext.h" #include "packets.h" #include "shash.h" +#include "tun-metadata.h" #include "unaligned.h" #include "util.h" #include "openvswitch/vlog.h" @@ -298,11 +299,11 @@ nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, } *header = ntohll(get_unaligned_be64(b->data)); } - if (nxm_length(*header) <= nxm_experimenter_len(*header)) { + if (nxm_length(*header) < nxm_experimenter_len(*header)) { VLOG_WARN_RL(&rl, "OXM header "NXM_HEADER_FMT" has invalid length %d " "(minimum is %d)", NXM_HEADER_ARGS(*header), nxm_length(*header), - nxm_header_len(*header) + 1); + nxm_header_len(*header)); goto error; } ofpbuf_pull(b, nxm_header_len(*header)); @@ -474,8 +475,6 @@ static enum ofperr nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) { - struct ofpbuf b; - ovs_assert((cookie != NULL) == (cookie_mask != NULL)); match_init_catchall(match); @@ -483,7 +482,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, *cookie = *cookie_mask = htonll(0); } - ofpbuf_use_const(&b, p, match_len); + struct ofpbuf b = ofpbuf_const_initializer(p, match_len); while (b.size) { const uint8_t *pos = b.data; const struct mf_field *field; @@ -510,7 +509,15 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, } else if (!mf_is_all_wild(field, &match->wc)) { error = OFPERR_OFPBMC_DUP_FIELD; } else { - mf_set(field, &value, &mask, match); + char *err_str; + + mf_set(field, &value, &mask, match, &err_str); + if (err_str) { + VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" " + "within match (%s)", pos - p, err_str); + free(err_str); + return OFPERR_OFPBMC_BAD_VALUE; + } } if (error) { @@ -621,15 +628,25 @@ oxm_pull_match_loose(struct ofpbuf *b, struct match *match) return oxm_pull_match__(b, false, match); } +/* Parses the OXM match description in the 'oxm_len' bytes in 'oxm'. Stores + * the result in 'match'. + * + * Fails with an error when encountering unknown OXM headers. + * + * Returns 0 if successful, otherwise an OpenFlow error code. */ +enum ofperr +oxm_decode_match(const void *oxm, size_t oxm_len, struct match *match) +{ + return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL); +} + /* Verify an array of OXM TLVs treating value of each TLV as a mask, * disallowing masks in each TLV and ignoring pre-requisites. */ enum ofperr oxm_pull_field_array(const void *fields_data, size_t fields_len, struct field_array *fa) { - struct ofpbuf b; - - ofpbuf_use_const(&b, fields_data, fields_len); + struct ofpbuf b = ofpbuf_const_initializer(fields_data, fields_len); while (b.size) { const uint8_t *pos = b.data; const struct mf_field *field; @@ -673,13 +690,16 @@ oxm_pull_field_array(const void *fields_data, size_t fields_len, * 'put' functions whose names end in 'm' add a field that might be wildcarded. * Other 'put' functions add exact-match fields. */ - -static void -nxm_put_unmasked(struct ofpbuf *b, enum mf_field_id field, - enum ofp_version version, const void *value, size_t n_bytes) +void +nxm_put__(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, + const void *value, const void *mask, size_t n_bytes) { - nx_put_header_len(b, field, version, false, n_bytes); + nx_put_header_len(b, field, version, !!mask, n_bytes); ofpbuf_put(b, value, n_bytes); + if (mask) { + ofpbuf_put(b, mask, n_bytes); + } + } static void @@ -688,11 +708,7 @@ nxm_put(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, { if (!is_all_zeros(mask, n_bytes)) { bool masked = !is_all_ones(mask, n_bytes); - nx_put_header_len(b, field, version, masked, n_bytes); - ofpbuf_put(b, value, n_bytes); - if (masked) { - ofpbuf_put(b, mask, n_bytes); - } + nxm_put__(b, field, version, value, masked ? mask : NULL, n_bytes); } } @@ -707,7 +723,7 @@ static void nxm_put_8(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, uint8_t value) { - nxm_put_unmasked(b, field, version, &value, sizeof value); + nxm_put__(b, field, version, &value, NULL, sizeof value); } static void @@ -721,7 +737,7 @@ static void nxm_put_16(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, ovs_be16 value) { - nxm_put_unmasked(b, field, version, &value, sizeof value); + nxm_put__(b, field, version, &value, NULL, sizeof value); } static void @@ -735,7 +751,7 @@ static void nxm_put_32(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, ovs_be32 value) { - nxm_put_unmasked(b, field, version, &value, sizeof value); + nxm_put__(b, field, version, &value, NULL, sizeof value); } static void @@ -745,13 +761,20 @@ nxm_put_64m(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, nxm_put(b, field, version, &value, &mask, sizeof value); } +static void +nxm_put_128m(struct ofpbuf *b, + enum mf_field_id field, enum ofp_version version, + const ovs_be128 value, const ovs_be128 mask) +{ + nxm_put(b, field, version, &value, &mask, sizeof(value)); +} + static void nxm_put_eth_masked(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, - const uint8_t value[ETH_ADDR_LEN], - const uint8_t mask[ETH_ADDR_LEN]) + const struct eth_addr value, const struct eth_addr mask) { - nxm_put(b, field, version, value, mask, ETH_ADDR_LEN); + nxm_put(b, field, version, value.ea, mask.ea, ETH_ADDR_LEN); } static void @@ -810,7 +833,7 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) flow->nw_tos & IP_ECN_MASK); } - if (!oxm && match->wc.masks.nw_ttl) { + if (match->wc.masks.nw_ttl) { nxm_put_8(b, MFF_IP_TTL, oxm, flow->nw_ttl); } @@ -894,7 +917,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, int match_len; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35); /* Metadata. */ if (match->wc.masks.dp_hash) { @@ -999,14 +1022,21 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id); /* Other tunnel metadata. */ + nxm_put_16m(b, MFF_TUN_FLAGS, oxm, + htons(flow->tunnel.flags), htons(match->wc.masks.tunnel.flags)); nxm_put_32m(b, MFF_TUN_SRC, oxm, flow->tunnel.ip_src, match->wc.masks.tunnel.ip_src); nxm_put_32m(b, MFF_TUN_DST, oxm, flow->tunnel.ip_dst, match->wc.masks.tunnel.ip_dst); + nxm_put_ipv6(b, MFF_TUN_IPV6_SRC, oxm, + &flow->tunnel.ipv6_src, &match->wc.masks.tunnel.ipv6_src); + nxm_put_ipv6(b, MFF_TUN_IPV6_DST, oxm, + &flow->tunnel.ipv6_dst, &match->wc.masks.tunnel.ipv6_dst); nxm_put_16m(b, MFF_TUN_GBP_ID, oxm, flow->tunnel.gbp_id, match->wc.masks.tunnel.gbp_id); nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm, flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags); + tun_metadata_to_nx_match(b, oxm, match); /* Registers. */ if (oxm < OFP15_VERSION) { @@ -1022,10 +1052,20 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, } } - /* Mark. */ + /* Packet mark. */ nxm_put_32m(b, MFF_PKT_MARK, oxm, htonl(flow->pkt_mark), htonl(match->wc.masks.pkt_mark)); + /* Connection tracking. */ + nxm_put_32m(b, MFF_CT_STATE, oxm, htonl(flow->ct_state), + htonl(match->wc.masks.ct_state)); + nxm_put_16m(b, MFF_CT_ZONE, oxm, htons(flow->ct_zone), + htons(match->wc.masks.ct_zone)); + nxm_put_32m(b, MFF_CT_MARK, oxm, htonl(flow->ct_mark), + htonl(match->wc.masks.ct_mark)); + nxm_put_128m(b, MFF_CT_LABEL, oxm, hton128(flow->ct_label), + hton128(match->wc.masks.ct_label)); + /* OpenFlow 1.1+ Metadata. */ nxm_put_64m(b, MFF_METADATA, oxm, flow->metadata, match->wc.masks.metadata); @@ -1067,7 +1107,7 @@ nx_put_match(struct ofpbuf *b, const struct match *match, } /* Appends to 'b' an struct ofp11_match_header followed by the OXM format that - * expresses 'cr', plus enough zero bytes to pad the data appended out to a + * expresses 'match', plus enough zero bytes to pad the data appended out to a * multiple of 8. * * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow @@ -1098,6 +1138,20 @@ oxm_put_match(struct ofpbuf *b, const struct match *match, return match_len; } +/* Appends to 'b' the OXM formats that expresses 'match', without header or + * padding. + * + * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow + * version in use as 'version'. + * + * This function can cause 'b''s data to be reallocated. */ +void +oxm_put_raw(struct ofpbuf *b, const struct match *match, + enum ofp_version version) +{ + nx_put_raw(b, version, match, 0, 0); +} + /* Appends to 'b' the nx_match format that expresses the tlv corresponding * to 'id'. If mask is not all-ones then it is also formated as the value * of the tlv. */ @@ -1168,8 +1222,10 @@ oxm_put_field_array(struct ofpbuf *b, const struct field_array *fa, for (i = 0; i < MFF_N_IDS; i++) { if (bitmap_is_set(fa->used.bm, i)) { - nxm_put_unmasked(b, i, version, &fa->value[i], - mf_from_id(i)->n_bytes); + int len = mf_field_len(mf_from_id(i), &fa->value[i], NULL, NULL); + nxm_put__(b, i, version, + &fa->value[i].u8 + mf_from_id(i)->n_bytes - len, NULL, + len); } } @@ -1210,13 +1266,17 @@ nx_put_entry(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, const union mf_value *value, const union mf_value *mask) { - int n_bytes = mf_from_id(field)->n_bytes; - bool masked = mask && !is_all_ones(mask, n_bytes); + const struct mf_field *mf = mf_from_id(field); + bool masked; + int len, offset; - nx_put_header(b, field, version, masked); - ofpbuf_put(b, value, n_bytes); + len = mf_field_len(mf, value, mask, &masked); + offset = mf->n_bytes - len; + + nx_put_header_len(b, field, version, masked, len); + ofpbuf_put(b, &value->u8 + offset, len); if (masked) { - ofpbuf_put(b, mask, n_bytes); + ofpbuf_put(b, &mask->u8 + offset, len); } } @@ -1227,15 +1287,12 @@ static void format_nxm_field_name(struct ds *, uint64_t header); char * nx_match_to_string(const uint8_t *p, unsigned int match_len) { - struct ofpbuf b; - struct ds s; - if (!match_len) { return xstrdup(""); } - ofpbuf_use_const(&b, p, match_len); - ds_init(&s); + struct ofpbuf b = ofpbuf_const_initializer(p, match_len); + struct ds s = DS_EMPTY_INITIALIZER; while (b.size) { union mf_value value; union mf_value mask; @@ -1409,6 +1466,8 @@ nx_match_from_string_raw(const char *s, struct ofpbuf *b) for (s += strspn(s, ", "); *s; s += strspn(s, ", ")) { const char *name; uint64_t header; + ovs_be64 nw_header; + ovs_be64 *header_ptr; int name_len; size_t n; @@ -1425,11 +1484,31 @@ nx_match_from_string_raw(const char *s, struct ofpbuf *b) s += name_len + 1; - nx_put_header__(b, header, false); + header_ptr = ofpbuf_put_uninit(b, nxm_header_len(header)); s = ofpbuf_put_hex(b, s, &n); if (n != nxm_field_bytes(header)) { - ovs_fatal(0, "%.2s: hex digits expected", s); + const struct mf_field *field = mf_from_oxm_header(header); + + if (field && field->variable_len) { + if (n <= field->n_bytes) { + int len = (nxm_hasmask(header) ? n * 2 : n) + + nxm_experimenter_len(header); + + header = NXM_HEADER(nxm_vendor(header), nxm_class(header), + nxm_field(header), + nxm_hasmask(header) ? 1 : 0, len); + } else { + ovs_fatal(0, "expected to read at most %d bytes but got " + "%"PRIuSIZE, field->n_bytes, n); + } + } else { + ovs_fatal(0, "expected to read %d bytes but got %"PRIuSIZE, + nxm_field_bytes(header), n); + } } + nw_header = htonll(header); + memcpy(header_ptr, &nw_header, nxm_header_len(header)); + if (nxm_hasmask(header)) { s += strspn(s, " "); if (*s != '/') { @@ -1545,8 +1624,8 @@ nxm_execute_reg_move(const struct ofpact_reg_move *move, 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_mask_field_and_prereqs(move->dst.field, wc); + mf_mask_field_and_prereqs(move->src.field, wc); /* A flow may wildcard nw_frag. Do nothing if setting a transport * header field on a packet that does not have them. */