This could fix using ovs-dpctl to add userspace datapath flows.
Signed-off-by: Jarno Rajahalme <[email protected]>
---
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
[email protected]
http://openvswitch.org/mailman/listinfo/dev