This could fix using ovs-dpctl to add userspace datapath flows. Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/dpctl.c | 4 +- lib/dpif-netdev.c | 85 ++++++++++++++++----------------------- lib/odp-util.c | 88 ++++++++++++++++++++++++++++++----------- lib/odp-util.h | 10 +++-- ofproto/ofproto-dpif-upcall.c | 8 +--- tests/test-odp.c | 8 ++-- 6 files changed, 114 insertions(+), 89 deletions(-)
diff --git a/lib/dpctl.c b/lib/dpctl.c index 623f5b1..25c8fbc 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -745,8 +745,8 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p) struct match match, match_filter; struct minimatch minimatch; - odp_flow_key_to_flow(f.key, f.key_len, &flow); - odp_flow_key_to_mask(f.mask, f.mask_len, &wc.masks, &flow); + odp_flow_key_to_flow_and_mask(f.key, f.key_len, f.mask, f.mask_len, + &flow, &wc.masks); match_init(&match, &flow, &wc); match_init(&match_filter, &flow_filter, &wc); diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 072ed5d..9b426a6 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1283,51 +1283,38 @@ dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow *netdev_flow, } static int -dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, - const struct nlattr *mask_key, - uint32_t mask_key_len, const struct flow *flow, - struct flow *mask) -{ - if (mask_key_len) { - enum odp_key_fitness fitness; - - fitness = odp_flow_key_to_mask(mask_key, mask_key_len, mask, flow); - if (fitness) { - /* This should not happen: it indicates that - * odp_flow_key_from_mask() and odp_flow_key_to_mask() - * disagree on the acceptable form of a mask. Log the problem - * as an error, with enough details to enable debugging. */ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - - if (!VLOG_DROP_ERR(&rl)) { - struct ds s; - - ds_init(&s); - odp_flow_format(key, key_len, mask_key, mask_key_len, NULL, &s, - true); - VLOG_ERR("internal error parsing flow mask %s (%s)", - ds_cstr(&s), odp_key_fitness_to_string(fitness)); - ds_destroy(&s); - } +dpif_netdev_match_from_nlattrs(const struct nlattr *key, uint32_t key_len, + const struct nlattr *mask, uint32_t mask_len, + struct match *match) +{ + enum odp_key_fitness fitness; + odp_port_t in_port; - return EINVAL; - } - } else { - enum mf_field_id id; - /* No mask key, unwildcard everything except fields whose - * prerequisities are not met. */ - memset(mask, 0x0, sizeof *mask); - - for (id = 0; id < MFF_N_IDS; ++id) { - /* Skip registers and metadata. */ - if (!(id >= MFF_REG0 && id < MFF_REG0 + FLOW_N_REGS) - && id != MFF_METADATA) { - const struct mf_field *mf = mf_from_id(id); - if (mf_are_prereqs_ok(mf, flow)) { - mf_mask_field(mf, mask); - } - } + fitness = odp_flow_key_to_flow_and_mask(key, key_len, mask, mask_len, + &match->flow, &match->wc.masks); + if (fitness) { + /* This should not happen: it indicates that odp_flow_key_from_flow() + * and odp_flow_key_to_flow() disagree on the acceptable form of a + * flow. Log the problem as an error, with enough details to enable + * debugging. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + + if (!VLOG_DROP_ERR(&rl)) { + struct ds s; + + ds_init(&s); + odp_flow_format(key, key_len, mask, mask_len, NULL, &s, true); + VLOG_ERR("internal error parsing flow or mask %s (%s)", + ds_cstr(&s), odp_key_fitness_to_string(fitness)); + ds_destroy(&s); } + + return EINVAL; + } + + in_port = match->flow.in_port.odp_port; + if (!is_valid_port_number(in_port) && in_port != ODPP_NONE) { + return EINVAL; } /* Force unwildcard the in_port. @@ -1336,7 +1323,7 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, * above because "everything" only includes the 16-bit OpenFlow port number * mask->in_port.ofp_port, which only covers half of the 32-bit datapath * port number mask->in_port.odp_port. */ - mask->in_port.odp_port = u32_to_odp(UINT32_MAX); + match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); return 0; } @@ -1464,13 +1451,9 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) struct match match; int error; - error = dpif_netdev_flow_from_nlattrs(put->key, put->key_len, &match.flow); - if (error) { - return error; - } - error = dpif_netdev_mask_from_nlattrs(put->key, put->key_len, - put->mask, put->mask_len, - &match.flow, &match.wc.masks); + error = dpif_netdev_match_from_nlattrs(put->key, put->key_len, + put->mask, put->mask_len, + &match); if (error) { return error; } diff --git a/lib/odp-util.c b/lib/odp-util.c index 77e6ec5..6b11d4b 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -29,6 +29,7 @@ #include "dpif.h" #include "dynamic-string.h" #include "flow.h" +#include "meta-flow.h" #include "netlink.h" #include "ofpbuf.h" #include "packets.h" @@ -2958,17 +2959,19 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len, static enum odp_key_fitness check_expectations(uint64_t present_attrs, int out_of_range_attr, uint64_t expected_attrs, - const struct nlattr *key, size_t key_len) + const struct nlattr *key, size_t key_len, bool exact) { uint64_t missing_attrs; uint64_t extra_attrs; - missing_attrs = expected_attrs & ~present_attrs; - if (missing_attrs) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10); - log_odp_key_attributes(&rl, "expected but not present", - missing_attrs, 0, key, key_len); - return ODP_FIT_TOO_LITTLE; + if (exact) { + missing_attrs = expected_attrs & ~present_attrs; + if (missing_attrs) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10); + log_odp_key_attributes(&rl, "expected but not present", + missing_attrs, 0, key, key_len); + return ODP_FIT_TOO_LITTLE; + } } extra_attrs = present_attrs & ~expected_attrs; @@ -3019,7 +3022,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], uint64_t present_attrs, int out_of_range_attr, uint64_t expected_attrs, struct flow *flow, const struct nlattr *key, size_t key_len, - const struct flow *src_flow) + const struct flow *src_flow, bool exact) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); bool is_mask = src_flow != flow; @@ -3253,7 +3256,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], done: return check_expectations(present_attrs, out_of_range_attr, expected_attrs, - key, key_len); + key, key_len, exact); } /* Parse 802.1Q header then encapsulated L3 attributes. */ @@ -3262,7 +3265,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], uint64_t present_attrs, int out_of_range_attr, uint64_t expected_attrs, struct flow *flow, const struct nlattr *key, size_t key_len, - const struct flow *src_flow) + const struct flow *src_flow, bool exact) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); bool is_mask = src_flow != flow; @@ -3286,7 +3289,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } } fitness = check_expectations(present_attrs, out_of_range_attr, - expected_attrs, key, key_len); + expected_attrs, key, key_len, exact); /* Set vlan_tci. * Remove the TPID from dl_type since it's not the real Ethertype. */ @@ -3326,7 +3329,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } encap_fitness = parse_l2_5_onward(attrs, present_attrs, out_of_range_attr, expected_attrs, flow, key, key_len, - src_flow); + src_flow, exact); /* The overall fitness is the worse of the outer and inner attributes. */ return MAX(fitness, encap_fitness); @@ -3334,7 +3337,8 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], static enum odp_key_fitness odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, - struct flow *flow, const struct flow *src_flow) + struct flow *flow, const struct flow *src_flow, + bool exact) { const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1]; uint64_t expected_attrs; @@ -3417,7 +3421,8 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, ? (src_flow->vlan_tci & htons(VLAN_CFI)) != 0 : src_flow->dl_type == htons(ETH_TYPE_VLAN)) { return parse_8021q_onward(attrs, present_attrs, out_of_range_attr, - expected_attrs, flow, key, key_len, src_flow); + expected_attrs, flow, key, key_len, src_flow, + exact); } if (is_mask) { flow->vlan_tci = htons(0xffff); @@ -3427,7 +3432,8 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, } } return parse_l2_5_onward(attrs, present_attrs, out_of_range_attr, - expected_attrs, flow, key, key_len, src_flow); + expected_attrs, flow, key, key_len, src_flow, + exact); } /* Converts the 'key_len' bytes of OVS_KEY_ATTR_* attributes in 'key' to a flow @@ -3444,23 +3450,57 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, * by looking at the attributes for lower-level protocols, e.g. if the network * protocol in OVS_KEY_ATTR_IPV4 or OVS_KEY_ATTR_IPV6 is IPPROTO_TCP then we * know that a OVS_KEY_ATTR_TCP attribute must appear and that otherwise it - * must be absent. */ + * must be absent. + * + * The presence of additional expected attributes is only enforced of 'exact' + * is 'true', otherwise it is assumed that the missing attributes are + * wildcarded. + */ enum odp_key_fitness odp_flow_key_to_flow(const struct nlattr *key, size_t key_len, struct flow *flow) { - return odp_flow_key_to_flow__(key, key_len, flow, flow); + return odp_flow_key_to_flow__(key, key_len, flow, flow, true); } -/* Converts the 'key_len' bytes of OVS_KEY_ATTR_* attributes in 'key' to a mask - * structure in 'mask'. 'flow' must be a previously translated flow - * corresponding to 'mask'. Returns an ODP_FIT_* value that indicates how well - * 'key' fits our expectations for what a flow key should contain. */ +/* Converts the 'key_len' and 'mask_len' bytes of OVS_KEY_ATTR_* attributes in + * 'key' and 'mask' to a flow structure in 'flow' and mask structure in + * 'fmask', respectively. + * Returns an ODP_FIT_* value that indicates how well 'key' and 'mask' fits our + * expectations for what a flow key should contain. + */ enum odp_key_fitness -odp_flow_key_to_mask(const struct nlattr *key, size_t key_len, - struct flow *mask, const struct flow *flow) +odp_flow_key_to_flow_and_mask(const struct nlattr *key, size_t key_len, + const struct nlattr *mask, size_t mask_len, + struct flow *flow, struct flow *fmask) { - return odp_flow_key_to_flow__(key, key_len, mask, flow); + enum odp_key_fitness key_fitness, mask_fitness; + enum mf_field_id id; + + key_fitness = odp_flow_key_to_flow__(key, key_len, flow, flow, false); + if (mask_len) { + mask_fitness = odp_flow_key_to_flow__(mask, mask_len, fmask, flow, + false); + /* The overall fitness is the worse of the two. */ + return MAX(key_fitness, mask_fitness); + } + + /* No mask key, unwildcard everything except fields whose + * prerequisities are not met. */ + memset(fmask, 0x0, sizeof *fmask); + + for (id = 0; id < MFF_N_IDS; ++id) { + /* Skip registers and metadata. */ + if (!(id >= MFF_REG0 && id < MFF_REG0 + FLOW_N_REGS) + && id != MFF_METADATA) { + const struct mf_field *mf = mf_from_id(id); + + if (mf_are_prereqs_ok(mf, flow)) { + mf_mask_field(mf, fmask); + } + } + } + return key_fitness; } /* Returns 'fitness' as a string, for use in debug messages. */ diff --git a/lib/odp-util.h b/lib/odp-util.h index 11b54dd..545febf 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -184,9 +184,13 @@ enum odp_key_fitness { }; enum odp_key_fitness odp_flow_key_to_flow(const struct nlattr *, size_t, struct flow *); -enum odp_key_fitness odp_flow_key_to_mask(const struct nlattr *key, size_t len, - struct flow *mask, - const struct flow *flow); +enum odp_key_fitness odp_flow_key_to_flow_and_mask(const struct nlattr *key, + size_t key_len, + const struct nlattr *mask, + size_t mask_len, + struct flow *flow, + struct flow *fmask); + const char *odp_key_fitness_to_string(enum odp_key_fitness); void commit_odp_tunnel_action(const struct flow *, struct flow *base, diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 8e890f8..984b910 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -1321,7 +1321,8 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, goto exit; } - if (odp_flow_key_to_flow(ukey->key, ukey->key_len, &flow) + if (odp_flow_key_to_flow_and_mask(ukey->key, ukey->key_len, + f->mask, f->mask_len, &flow, &dp_mask) == ODP_FIT_ERROR) { goto exit; } @@ -1369,11 +1370,6 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, goto exit; } - if (odp_flow_key_to_mask(f->mask, f->mask_len, &dp_mask, &flow) - == ODP_FIT_ERROR) { - goto exit; - } - /* Since the kernel is free to ignore wildcarded bits in the mask, we can't * directly check that the masks are the same. Instead we check that the * mask in the kernel is more specific i.e. less wildcarded, than what diff --git a/tests/test-odp.c b/tests/test-odp.c index b8d4f80..3974127 100644 --- a/tests/test-odp.c +++ b/tests/test-odp.c @@ -185,9 +185,11 @@ parse_filter(char *filter_parse) struct match match, match_filter; struct minimatch minimatch; - odp_flow_key_to_flow(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow); - odp_flow_key_to_mask(ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), &wc.masks, - &flow); + odp_flow_key_to_flow_and_mask(ofpbuf_data(&odp_key), + ofpbuf_size(&odp_key), + ofpbuf_data(&odp_mask), + ofpbuf_size(&odp_mask), + &flow, &wc.masks); match_init(&match, &flow, &wc); match_init(&match_filter, &flow_filter, &wc); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev