[ovs-dev] [PATCH branch-2.3] odp-util: Return exact mask if netlink mask attribute is missing.

Daniele Di Proietto diproiettod at vmware.com
Tue Dec 15 01:23:36 UTC 2015


In the ODP context an empty mask netlink attribute usually means that
the flow should be an exact match.

odp_flow_key_to_mask() instead returns a struct flow_wildcards
with matches only on recirc_id and vlan_tci.

A more appropriate behavior is to handle a missing (zero length) netlink
mask specially (like we do in userspace and Linux datapath) and create
an exact match flow_wildcards from the original flow.

This fixes a bug in revalidate_ukey(): every flow created with
megaflows disabled would be revalidated away, because the mask would
seem too generic. (Another possible fix would be to handle the special
case of a missing mask in revalidate_ukey(), but this seems a more
generic solution).

Signed-off-by: Daniele Di Proietto <diproiettod at vmware.com>
Acked-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/dpif-netdev.c             | 65 +++++++++++++++----------------------------
 lib/odp-util.c                | 26 +++++++++++++++--
 lib/odp-util.h                |  2 +-
 ofproto/ofproto-dpif-upcall.c |  5 ++--
 tests/test-odp.c              |  4 +--
 utilities/ovs-dpctl.c         |  2 +-
 6 files changed, 54 insertions(+), 50 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 78f8636..5fe4430 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1100,48 +1100,29 @@ 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);
-            }
+                              struct flow_wildcards *mask)
+{
+    enum odp_key_fitness fitness;
 
-            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_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);
         }
+        return EINVAL;
     }
 
     /* Force unwildcard the in_port.
@@ -1150,7 +1131,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);
+    mask->masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
 
     return 0;
 }
@@ -1313,7 +1294,7 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
     }
     error = dpif_netdev_mask_from_nlattrs(put->key, put->key_len,
                                           put->mask, put->mask_len,
-                                          &flow, &wc.masks);
+                                          &flow, &wc);
     if (error) {
         return error;
     }
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 3ef13b4..59466cc 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"
@@ -3422,9 +3423,30 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
  * 'key' 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)
+                     struct flow_wildcards *mask, const struct flow *flow)
 {
-   return odp_flow_key_to_flow__(key, key_len, mask, flow);
+    if (key_len) {
+        return odp_flow_key_to_flow__(key, key_len, &mask->masks, flow);
+    } else {
+        enum mf_field_id id;
+        /* A missing mask means that the flow should be exact matched.
+         * Generate an appropriate exact wildcard for the flow by
+         * unwildcarding 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->masks);
+                }
+            }
+        }
+        return ODP_FIT_PERFECT;
+    }
 }
 
 /* Returns 'fitness' as a string, for use in debug messages. */
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 0dfbcca..ff6133d 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -173,7 +173,7 @@ 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,
+                                          struct flow_wildcards *mask,
                                           const struct flow *flow);
 const char *odp_key_fitness_to_string(enum odp_key_fitness);
 
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 193e6b7..6123590 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -1217,15 +1217,16 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
 {
     uint64_t slow_path_buf[128 / 8];
     struct xlate_out xout, *xoutp;
+    struct flow_wildcards dp_mask;
     struct netflow *netflow;
     struct ofproto_dpif *ofproto;
     struct dpif_flow_stats push;
     struct ofpbuf xout_actions;
-    struct flow flow, dp_mask;
     uint32_t *dp32, *xout32;
     odp_port_t odp_in_port;
     struct xlate_in xin;
     long long int last_used;
+    struct flow flow;
     int error;
     size_t i;
     bool may_learn, ok;
@@ -1313,7 +1314,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
      * mask in the kernel is more specific i.e. less wildcarded, than what
      * we've calculated here.  This guarantees we don't catch any packets we
      * shouldn't with the megaflow. */
-    dp32 = (uint32_t *) &dp_mask;
+    dp32 = (uint32_t *) &dp_mask.masks;
     xout32 = (uint32_t *) &xout.wc.masks;
     for (i = 0; i < FLOW_U32S; i++) {
         if ((dp32[i] | xout32[i]) != dp32[i]) {
diff --git a/tests/test-odp.c b/tests/test-odp.c
index 30cdbbf..ab3dfd4 100644
--- a/tests/test-odp.c
+++ b/tests/test-odp.c
@@ -186,8 +186,8 @@ parse_filter(char *filter_parse)
             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_mask(ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask),
+                                 &wc, &flow);
             match_init(&match, &flow, &wc);
 
             match_init(&match_filter, &flow_filter, &wc);
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index ccc55b5..7a38ff6 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -807,7 +807,7 @@ dpctl_dump_flows(int argc, char *argv[])
             struct minimatch minimatch;
 
             odp_flow_key_to_flow(key, key_len, &flow);
-            odp_flow_key_to_mask(mask, mask_len, &wc.masks, &flow);
+            odp_flow_key_to_mask(mask, mask_len, &wc, &flow);
             match_init(&match, &flow, &wc);
 
             match_init(&match_filter, &flow_filter, &wc);
-- 
2.1.4




More information about the dev mailing list