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

Reply via email to