[ovs-dev] [generic tci mask 4/8] flow: Move functions for dealing with wildcard bit counts to ofp-util.

Ben Pfaff blp at nicira.com
Wed Nov 10 23:37:59 UTC 2010


These functions are really OpenFlow-specific, and they will not be used
directly by the flow code soon, so move them to ofp-util.
---
 lib/flow.c              |   42 +++++-------------------------------------
 lib/flow.h              |    1 -
 lib/ofp-util.c          |   43 +++++++++++++++++++++++++++++++++++++++----
 lib/ofp-util.h          |    5 +++++
 lib/packets.h           |   10 ++++++++++
 tests/test-classifier.c |    8 ++++++--
 6 files changed, 65 insertions(+), 44 deletions(-)

diff --git a/lib/flow.c b/lib/flow.c
index 082a1df..a174a11 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -24,6 +24,7 @@
 #include "coverage.h"
 #include "dynamic-string.h"
 #include "hash.h"
+#include "ofp-util.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
 #include "openvswitch/datapath-protocol.h"
@@ -355,22 +356,6 @@ flow_print(FILE *stream, const struct flow *flow)
 
 /* flow_wildcards functions. */
 
-/* Given the wildcard bit count in bits 'shift' through 'shift + 5' (inclusive)
- * of 'wildcards', returns a 32-bit bit mask with a 1 in each bit that must
- * match and a 0 in each bit that is wildcarded.
- *
- * The bits in 'wildcards' are in the format used in enum ofp_flow_wildcards: 0
- * is exact match, 1 ignores the LSB, 2 ignores the 2 least-significant bits,
- * ..., 32 and higher wildcard the entire field.  This is the *opposite* of the
- * usual convention where e.g. /24 indicates that 8 bits (not 24 bits) are
- * wildcarded. */
-ovs_be32
-flow_nw_bits_to_mask(uint32_t wildcards, int shift)
-{
-    wildcards = (wildcards >> shift) & 0x3f;
-    return wildcards < 32 ? htonl(~((1u << wildcards) - 1)) : 0;
-}
-
 /* Return 'wildcards' in "normal form":
  *
  *   - Forces unknown bits to 0.
@@ -401,8 +386,8 @@ void
 flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards)
 {
     wc->wildcards = flow_wildcards_normalize(wildcards) | FWW_REGS;
-    wc->nw_src_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_SRC_SHIFT);
-    wc->nw_dst_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_DST_SHIFT);
+    wc->nw_src_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_SRC_SHIFT);
+    wc->nw_dst_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_DST_SHIFT);
     memset(wc->reg_masks, 0, sizeof wc->reg_masks);
 }
 
@@ -509,30 +494,13 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
             || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask);
 }
 
-static int
-count_ones(ovs_be32 mask)
-{
-#if __GNUC__ >= 4
-    return __builtin_popcount(mask);
-#else
-    int bits;
-
-    for (bits = 0; mask; bits++) {
-        mask &= mask - 1;
-    }
-
-    return bits;
-#endif
-}
-
 static bool
 set_nw_mask(struct flow_wildcards *wc, ovs_be32 mask,
             ovs_be32 *maskp, int shift)
 {
-    int wcbits = 32 - count_ones(mask);
-    if (flow_nw_bits_to_mask(wcbits, 0) == mask) {
+    if (ip_is_cidr(mask)) {
         wc->wildcards &= ~(0x3f << shift);
-        wc->wildcards |= wcbits << shift;
+        wc->wildcards |= ofputil_netmask_to_wcbits(mask) << shift;
         *maskp = mask;
         return true;
     } else {
diff --git a/lib/flow.h b/lib/flow.h
index 1099f9f..2f7f01a 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -144,7 +144,6 @@ struct flow_wildcards {
     ovs_be32 nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
 };
 
-ovs_be32 flow_nw_bits_to_mask(uint32_t wildcards, int shift);
 void flow_wildcards_init(struct flow_wildcards *, uint32_t wildcards);
 void flow_wildcards_init_exact(struct flow_wildcards *);
 
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 81a5dad..6712dd1 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -32,6 +32,41 @@ VLOG_DEFINE_THIS_MODULE(ofp_util);
  * in the peer and so there's not much point in showing a lot of them. */
 static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
+/* Given the wildcard bit count in bits 0...5 (inclusive) of 'wildcards',
+ * returns an IP netmask with a 1 in each bit that must match and a 0 in each
+ * bit that is wildcarded.
+ *
+ * The bits in 'wildcards' are in the format used in enum ofp_flow_wildcards: 0
+ * is exact match, 1 ignores the LSB, 2 ignores the 2 least-significant bits,
+ * ..., 32 and higher wildcard the entire field.  This is the *opposite* of the
+ * usual convention where e.g. /24 indicates that 8 bits (not 24 bits) are
+ * wildcarded. */
+ovs_be32
+ofputil_wcbits_to_netmask(int wcbits)
+{
+    wcbits &= wcbits;
+    return wcbits < 32 ? htonl(~((1u << wcbits) - 1)) : 0;
+}
+
+/* Given the IP netmask 'netmask', returns the number of bits of the IP address
+ * that it wildcards.  The return value is only accurate if 'netmask' is a CIDR
+ * netmask (see ip_is_cidr()). */
+int
+ofputil_netmask_to_wcbits(ovs_be32 netmask)
+{
+#if __GNUC__ >= 4
+    return netmask == htonl(0) ? 32 : __builtin_ctz(ntohl(netmask));
+#else
+    int wcbits;
+
+    for (wcbits = 32; netmask; wcbits--) {
+        netmask &= netmask - 1;
+    }
+
+    return wcbits;
+#endif
+}
+
 /* XXX we should really use consecutive xids to avoid probabilistic
  * failures. */
 static inline uint32_t
@@ -744,10 +779,10 @@ normalize_match(struct ofp_match *m)
             m->tp_src = m->tp_dst = 0;
         }
         if (wc & OFPFW_NW_SRC_MASK) {
-            m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT);
+            m->nw_src &= ofputil_wcbits_to_netmask(wc >> OFPFW_NW_SRC_SHIFT);
         }
         if (wc & OFPFW_NW_DST_MASK) {
-            m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
+            m->nw_dst &= ofputil_wcbits_to_netmask(wc >> OFPFW_NW_DST_SHIFT);
         }
         if (wc & OFPFW_NW_TOS) {
             m->nw_tos = 0;
@@ -759,10 +794,10 @@ normalize_match(struct ofp_match *m)
             m->nw_proto = 0;
         }
         if (wc & OFPFW_NW_SRC_MASK) {
-            m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT);
+            m->nw_src &= ofputil_wcbits_to_netmask(wc >> OFPFW_NW_SRC_SHIFT);
         }
         if (wc & OFPFW_NW_DST_MASK) {
-            m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
+            m->nw_dst &= ofputil_wcbits_to_netmask(wc >> OFPFW_NW_DST_SHIFT);
         }
         m->tp_src = m->tp_dst = m->nw_tos = 0;
     } else {
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 6f8c259..d3dd692 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -26,6 +26,11 @@
 struct ofpbuf;
 struct ofp_action_header;
 
+/* Converting OFPFW_NW_SRC_MASK and OFPFW_NW_DST_MASK wildcard bit counts to
+ * and from IP bitmasks. */
+ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
+int ofputil_netmask_to_wcbits(ovs_be32 netmask);
+
 /* OpenFlow protocol utility functions. */
 void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
 void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
diff --git a/lib/packets.h b/lib/packets.h
index af028eb..16322d6 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <string.h>
 #include "compiler.h"
+#include "openvswitch/types.h"
 #include "random.h"
 #include "util.h"
 
@@ -246,6 +247,15 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
         ((uint8_t *) ip)[2],                    \
         ((uint8_t *) ip)[3]
 
+/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N
+ * high-order 1-bits and 32-N low-order 0-bits. */
+static inline bool
+ip_is_cidr(ovs_be32 netmask)
+{
+    uint32_t x = ~ntohl(netmask);
+    return !(x & (x + 1));
+}
+
 #define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4)
 #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
 #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 3049810..2de1eb3 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -32,6 +32,7 @@
 #include "byte-order.h"
 #include "command-line.h"
 #include "flow.h"
+#include "ofp-util.h"
 #include "packets.h"
 #include "unaligned.h"
 
@@ -200,9 +201,12 @@ match(const struct cls_rule *wild, const struct flow *fixed)
         if (wild->wc.wildcards & f->wildcards) {
             uint32_t test = get_unaligned_u32(wild_field);
             uint32_t ip = get_unaligned_u32(fixed_field);
-            int shift = (f_idx == CLS_F_IDX_NW_SRC
+            uint32_t mask;
+            int shift;
+
+            shift = (f_idx == CLS_F_IDX_NW_SRC
                          ? OFPFW_NW_SRC_SHIFT : OFPFW_NW_DST_SHIFT);
-            uint32_t mask = flow_nw_bits_to_mask(wild->wc.wildcards, shift);
+            mask = ofputil_wcbits_to_netmask(wild->wc.wildcards) >> shift;
             if (!((test ^ ip) & mask)) {
                 continue;
             }
-- 
1.7.1





More information about the dev mailing list