X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fmeta-flow.c;h=902a21d05a573e3d5e2cdced89447203ce792f37;hb=015ac88281952a1b43ad46e9e6300db1c6e3647b;hp=067720255fa114f292e67b40a4db92e6848729ad;hpb=4e022ec09e14ac89add74c1b4b8e3ff3873edbf0;p=sliver-openvswitch.git diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 067720255..902a21d05 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -27,6 +27,7 @@ #include "dynamic-string.h" #include "ofp-errors.h" #include "ofp-util.h" +#include "ovs-thread.h" #include "packets.h" #include "random.h" #include "shash.h" @@ -136,14 +137,14 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { 0, NULL, 0, NULL, }, { - MFF_SKB_MARK, "skb_mark", NULL, + MFF_PKT_MARK, "pkt_mark", NULL, MF_FIELD_SIZES(be32), - MFM_NONE, + MFM_FULLY, MFS_HEXADECIMAL, MFP_NONE, - false, - 0, NULL, - 0, NULL, + true, + NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK", + NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK", }, #define REGISTER(IDX) \ @@ -498,6 +499,26 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { OXM_OF_UDP_DST, "OXM_OF_UDP_DST", }, + { + MFF_SCTP_SRC, "sctp_src", NULL, + MF_FIELD_SIZES(be16), + MFM_FULLY, + MFS_DECIMAL, + MFP_SCTP, + true, + OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC", + OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC", + }, { + MFF_SCTP_DST, "sctp_dst", NULL, + MF_FIELD_SIZES(be16), + MFM_FULLY, + MFS_DECIMAL, + MFP_SCTP, + true, + OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST", + OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST", + }, + { MFF_ICMPV4_TYPE, "icmp_type", NULL, MF_FIELD_SIZES(u8), @@ -580,13 +601,17 @@ struct nxm_field { }; /* Contains 'struct nxm_field's. */ -static struct hmap all_fields = HMAP_INITIALIZER(&all_fields); +static struct hmap all_fields; + +/* Maps from an mf_field's 'name' or 'extra_name' to the mf_field. */ +static struct shash mf_by_name; /* Rate limit for parse errors. These always indicate a bug in an OpenFlow * controller and so there's not much point in showing a lot of them. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); const struct mf_field *mf_from_nxm_header__(uint32_t header); +static void nxm_init(void); /* Returns the field with the given 'id'. */ const struct mf_field * @@ -601,19 +626,7 @@ mf_from_id(enum mf_field_id id) const struct mf_field * mf_from_name(const char *name) { - static struct shash mf_by_name = SHASH_INITIALIZER(&mf_by_name); - - if (shash_is_empty(&mf_by_name)) { - const struct mf_field *mf; - - for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) { - shash_add_once(&mf_by_name, mf->name, mf); - if (mf->extra_name) { - shash_add_once(&mf_by_name, mf->extra_name, mf); - } - } - } - + nxm_init(); return shash_find_data(&mf_by_name, name); } @@ -641,24 +654,36 @@ nxm_init_add_field(const struct mf_field *mf, uint32_t header) } static void -nxm_init(void) +nxm_do_init(void) { const struct mf_field *mf; + hmap_init(&all_fields); + shash_init(&mf_by_name); for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) { nxm_init_add_field(mf, mf->nxm_header); if (mf->oxm_header != mf->nxm_header) { nxm_init_add_field(mf, mf->oxm_header); } + + shash_add_once(&mf_by_name, mf->name, mf); + if (mf->extra_name) { + shash_add_once(&mf_by_name, mf->extra_name, mf); + } } } +static void +nxm_init(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, nxm_do_init); +} + const struct mf_field * mf_from_nxm_header(uint32_t header) { - if (hmap_is_empty(&all_fields)) { - nxm_init(); - } + nxm_init(); return mf_from_nxm_header__(header); } @@ -701,8 +726,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) return !wc->masks.in_port.ofp_port; case MFF_SKB_PRIORITY: return !wc->masks.skb_priority; - case MFF_SKB_MARK: - return !wc->masks.skb_mark; + case MFF_PKT_MARK: + return !wc->masks.pkt_mark; CASE_MFF_REGS: return !wc->masks.regs[mf->id - MFF_REG0]; @@ -776,11 +801,13 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: case MFF_ICMPV4_TYPE: case MFF_ICMPV6_TYPE: return !wc->masks.tp_src; case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: case MFF_ICMPV4_CODE: case MFF_ICMPV6_CODE: return !wc->masks.tp_dst; @@ -861,6 +888,8 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow) return is_ip_any(flow) && flow->nw_proto == IPPROTO_TCP; case MFP_UDP: return is_ip_any(flow) && flow->nw_proto == IPPROTO_UDP; + case MFP_SCTP: + return is_ip_any(flow) && flow->nw_proto == IPPROTO_SCTP; case MFP_ICMPV4: return is_icmpv4(flow); case MFP_ICMPV6: @@ -907,7 +936,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_METADATA: case MFF_IN_PORT: case MFF_SKB_PRIORITY: - case MFF_SKB_MARK: + case MFF_PKT_MARK: CASE_MFF_REGS: case MFF_ETH_SRC: case MFF_ETH_DST: @@ -927,6 +956,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_TCP_DST: case MFF_UDP_SRC: case MFF_UDP_DST: + case MFF_SCTP_SRC: + case MFF_SCTP_DST: case MFF_ICMPV4_TYPE: case MFF_ICMPV4_CODE: case MFF_ICMPV6_TYPE: @@ -1021,8 +1052,8 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, value->be32 = htonl(flow->skb_priority); break; - case MFF_SKB_MARK: - value->be32 = htonl(flow->skb_mark); + case MFF_PKT_MARK: + value->be32 = htonl(flow->pkt_mark); break; CASE_MFF_REGS: @@ -1137,11 +1168,13 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: value->be16 = flow->tp_src; break; case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: value->be16 = flow->tp_dst; break; @@ -1211,8 +1244,8 @@ mf_set_value(const struct mf_field *mf, match_set_skb_priority(match, ntohl(value->be32)); break; - case MFF_SKB_MARK: - match_set_skb_mark(match, ntohl(value->be32)); + case MFF_PKT_MARK: + match_set_pkt_mark(match, ntohl(value->be32)); break; CASE_MFF_REGS: @@ -1327,11 +1360,13 @@ mf_set_value(const struct mf_field *mf, case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: match_set_tp_src(match, value->be16); break; case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: match_set_tp_dst(match, value->be16); break; @@ -1400,8 +1435,8 @@ mf_set_flow_value(const struct mf_field *mf, flow->skb_priority = ntohl(value->be32); break; - case MFF_SKB_MARK: - flow->skb_mark = ntohl(value->be32); + case MFF_PKT_MARK: + flow->pkt_mark = ntohl(value->be32); break; CASE_MFF_REGS: @@ -1519,11 +1554,13 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: flow->tp_src = value->be16; break; case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: flow->tp_dst = value->be16; break; @@ -1602,9 +1639,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match) match->wc.masks.skb_priority = 0; break; - case MFF_SKB_MARK: - match->flow.skb_mark = 0; - match->wc.masks.skb_mark = 0; + case MFF_PKT_MARK: + match->flow.pkt_mark = 0; + match->wc.masks.pkt_mark = 0; break; CASE_MFF_REGS: @@ -1722,6 +1759,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match) case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: case MFF_ICMPV4_TYPE: case MFF_ICMPV6_TYPE: match->wc.masks.tp_src = htons(0); @@ -1730,6 +1768,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match) case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: case MFF_ICMPV4_CODE: case MFF_ICMPV6_CODE: match->wc.masks.tp_dst = htons(0); @@ -1775,7 +1814,6 @@ mf_set(const struct mf_field *mf, switch (mf->id) { case MFF_IN_PORT: case MFF_IN_PORT_OXM: - case MFF_SKB_MARK: case MFF_SKB_PRIORITY: case MFF_ETH_TYPE: case MFF_DL_VLAN: @@ -1824,6 +1862,11 @@ mf_set(const struct mf_field *mf, ntohl(value->be32), ntohl(mask->be32)); break; + case MFF_PKT_MARK: + match_set_pkt_mark_masked(match, ntohl(value->be32), + ntohl(mask->be32)); + break; + case MFF_ETH_DST: match_set_dl_dst_masked(match, value->mac, mask->mac); break; @@ -1892,11 +1935,13 @@ mf_set(const struct mf_field *mf, case MFF_TCP_SRC: case MFF_UDP_SRC: + case MFF_SCTP_SRC: match_set_tp_src_masked(match, value->be16, mask->be16); break; case MFF_TCP_DST: case MFF_UDP_DST: + case MFF_SCTP_DST: match_set_tp_dst_masked(match, value->be16, mask->be16); break; @@ -1912,23 +1957,26 @@ mf_check__(const struct mf_subfield *sf, const struct flow *flow, { if (!sf->field) { VLOG_WARN_RL(&rl, "unknown %s field", type); + return OFPERR_OFPBAC_BAD_SET_TYPE; } else if (!sf->n_bits) { VLOG_WARN_RL(&rl, "zero bit %s field %s", type, sf->field->name); + return OFPERR_OFPBAC_BAD_SET_LEN; } else if (sf->ofs >= sf->field->n_bits) { VLOG_WARN_RL(&rl, "bit offset %d exceeds %d-bit width of %s field %s", sf->ofs, sf->field->n_bits, type, sf->field->name); + return OFPERR_OFPBAC_BAD_SET_LEN; } else if (sf->ofs + sf->n_bits > sf->field->n_bits) { VLOG_WARN_RL(&rl, "bit offset %d and width %d exceeds %d-bit width " "of %s field %s", sf->ofs, sf->n_bits, sf->field->n_bits, type, sf->field->name); + return OFPERR_OFPBAC_BAD_SET_LEN; } else if (flow && !mf_are_prereqs_ok(sf->field, flow)) { VLOG_WARN_RL(&rl, "%s field %s lacks correct prerequisites", type, sf->field->name); + return OFPERR_OFPBAC_MATCH_INCONSISTENT; } else { return 0; } - - return OFPERR_OFPBAC_BAD_ARGUMENT; } /* Checks whether 'sf' is valid for reading a subfield out of 'flow'. Returns @@ -1950,7 +1998,7 @@ mf_check_dst(const struct mf_subfield *sf, const struct flow *flow) if (!error && !sf->field->writable) { VLOG_WARN_RL(&rl, "destination field %s is not writable", sf->field->name); - return OFPERR_OFPBAC_BAD_ARGUMENT; + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } return error; } @@ -1980,7 +2028,7 @@ mf_random_value(const struct mf_field *mf, union mf_value *value) case MFF_TUN_FLAGS: case MFF_METADATA: case MFF_IN_PORT: - case MFF_SKB_MARK: + case MFF_PKT_MARK: case MFF_SKB_PRIORITY: CASE_MFF_REGS: case MFF_ETH_SRC: @@ -2001,6 +2049,8 @@ mf_random_value(const struct mf_field *mf, union mf_value *value) case MFF_TCP_DST: case MFF_UDP_SRC: case MFF_UDP_DST: + case MFF_SCTP_SRC: + case MFF_SCTP_DST: case MFF_ICMPV4_TYPE: case MFF_ICMPV4_CODE: case MFF_ICMPV6_TYPE: @@ -2112,20 +2162,25 @@ mf_from_ethernet_string(const struct mf_field *mf, const char *s, uint8_t mac[ETH_ADDR_LEN], uint8_t mask[ETH_ADDR_LEN]) { - ovs_assert(mf->n_bytes == ETH_ADDR_LEN); + int n; - switch (sscanf(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask))){ - case ETH_ADDR_SCAN_COUNT * 2: - return NULL; + ovs_assert(mf->n_bytes == ETH_ADDR_LEN); - case ETH_ADDR_SCAN_COUNT: + n = -1; + if (sscanf(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) > 0 + && n == strlen(s)) { memset(mask, 0xff, ETH_ADDR_LEN); return NULL; + } - default: - return xasprintf("%s: invalid Ethernet address", s); + n = -1; + if (sscanf(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT"%n", + ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask), &n) > 0 + && n == strlen(s)) { + return NULL; } + + return xasprintf("%s: invalid Ethernet address", s); } static char * @@ -2641,7 +2696,7 @@ mf_parse_subfield_name(const char *name, int name_len, bool *wild) * bit indexes. "..end" may be omitted to indicate a single bit. "start..end" * may both be omitted (the [] are still required) to indicate an entire * field. */ -char * +char * WARN_UNUSED_RESULT mf_parse_subfield__(struct mf_subfield *sf, const char **sp) { const struct mf_field *field; @@ -2696,24 +2751,23 @@ mf_parse_subfield__(struct mf_subfield *sf, const char **sp) return NULL; } -/* Parses a subfield from the beginning of 's' into 'sf'. Returns the first - * byte in 's' following the parsed string. - * - * Exits with an error message if 's' has incorrect syntax. +/* Parses a subfield from the entirety of 's' into 'sf'. Returns NULL if + * successful, otherwise a malloc()'d string describing the error. The caller + * is responsible for freeing the returned string. * * The syntax parsed from 's' takes the form "header[start..end]" where * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive) * bit indexes. "..end" may be omitted to indicate a single bit. "start..end" * may both be omitted (the [] are still required) to indicate an entire * field. */ -const char * +char * WARN_UNUSED_RESULT mf_parse_subfield(struct mf_subfield *sf, const char *s) { - char *msg = mf_parse_subfield__(sf, &s); - if (msg) { - ovs_fatal(0, "%s", msg); + char *error = mf_parse_subfield__(sf, &s); + if (!error && s[0]) { + error = xstrdup("unexpected input following field syntax"); } - return s; + return error; } void