Data structure to store allowed versions as a bitmap.

Bit offsets correspond to ofp_version numbers which in turn
correspond to wire-protocol numbers for Open Flow versions..
E.g. (1 << OFP10_VERSION) is the mask for Open Flow 1.1.
If the bit for a version is set then it is allowed, otherwise it is
disallowed.

This is in preparation for allowing the range of allowed OpenFlow
versions to be configured.

Signed-off-by: Simon Horman <ho...@verge.net.au>
---
 lib/bitmap.c   |   31 ++++++++
 lib/bitmap.h   |    3 +
 lib/ofp-util.c |  243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ofp-util.h |   53 ++++++++++++
 4 files changed, 330 insertions(+)

diff --git a/lib/bitmap.c b/lib/bitmap.c
index d607526..a2960f8 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -89,3 +89,34 @@ bitmap_scan(const unsigned long int *bitmap, size_t start, 
size_t end)
     }
     return i;
 }
+
+/* Scans 'bitmap' from bit offset 'end' to 'start', excluding 'end' itself.
+ * Returns the bit offset of the highest-numbered bit set to 1, or 'end' if
+ * all of the bits are set to 0. */
+size_t
+bitmap_scanr(const unsigned long int *bitmap, size_t start, size_t end)
+{
+    /* XXX slow */
+    size_t i = end - 1;
+
+    do {
+        if (bitmap_is_set(bitmap, i)) {
+            return i;
+        }
+    } while (i-- != start);
+    return end;
+}
+
+/* Performs the bitwise and of bitmaps 'a' and 'b' starting at 'start' and
+ * ending at 'end', excluding 'end' itself. The result is stored in 'b'. */
+void
+bitmap_and(const unsigned long int *a, unsigned long int *b,
+           size_t start, size_t end)
+{
+    /* XXX slow */
+    size_t i;
+
+    for (i = start; i < end; i++) {
+        bitmap_set(b, i, bitmap_is_set(a, i) && bitmap_is_set(b, i));
+    }
+}
diff --git a/lib/bitmap.h b/lib/bitmap.h
index 8980496..1b0bebe 100644
--- a/lib/bitmap.h
+++ b/lib/bitmap.h
@@ -99,6 +99,9 @@ void bitmap_set_multiple(unsigned long *, size_t start, 
size_t count,
                          bool value);
 bool bitmap_equal(const unsigned long *, const unsigned long *, size_t n);
 size_t bitmap_scan(const unsigned long int *, size_t start, size_t end);
+size_t bitmap_scanr(const unsigned long int *, size_t start, size_t end);
+void bitmap_and(const unsigned long int *a, unsigned long int *b,
+                size_t start, size_t end);
 
 #define BITMAP_FOR_EACH_1(IDX, SIZE, BITMAP) \
     for ((IDX) = bitmap_scan(BITMAP, 0, SIZE); (IDX) < (SIZE); \
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 9527d2c..94354fe 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include "ofp-print.h"
+#include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <sys/types.h>
@@ -23,6 +24,7 @@
 #include <netinet/icmp6.h>
 #include <stdlib.h>
 #include "autopath.h"
+#include "bitmap.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "classifier.h"
@@ -845,6 +847,69 @@ ofputil_protocols_from_string(const char *s)
     return protocols;
 }
 
+static enum ofp_version
+ofputil_version_from_string(const char *s)
+{
+    if (!strcasecmp(s, "OpenFlow10")) {
+        return OFP10_VERSION;
+    }
+    if (!strcasecmp(s, "OpenFlow11")) {
+        return OFP11_VERSION;
+    }
+    if (!strcasecmp(s, "OpenFlow12")) {
+        return OFP12_VERSION;
+    }
+    VLOG_FATAL("Unknown OpenFlow version: \"%s\"", s);
+}
+
+static bool
+is_delimiter(char c)
+{
+    return isspace(c) || c == ',';
+}
+
+void
+ofputil_versions_from_string(const char *s,
+                             struct ofputil_version_bitmap *ovb)
+{
+    size_t i = 0;
+
+    while (s[i]) {
+        size_t j;
+        enum ofp_version version;
+        char *key;
+
+        if (is_delimiter(s[i])) {
+            i++;
+            continue;
+        }
+        j = 0;
+        while (s[i + j] && !is_delimiter(s[i + j])) {
+            j++;
+        }
+        key = xmemdup0(s + i, j);
+        version = ofputil_version_from_string(key);
+        free(key);
+        ofputil_version_bitmap_set1(ovb, version);
+        i += j;
+    }
+}
+
+const char *
+ofputil_version_to_string(enum ofp_version ofp_version)
+{
+    switch (ofp_version) {
+    case OFP10_VERSION:
+        return "OpenFlow10";
+    case OFP11_VERSION:
+        return "OpenFlow11";
+    case OFP12_VERSION:
+        return "OpenFlow12";
+    default:
+        NOT_REACHED();
+    }
+}
+
 bool
 ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format)
 {
@@ -973,6 +1038,184 @@ ofputil_usable_protocols(const struct match *match)
     return OFPUTIL_P_ANY;
 }
 
+/* Set initial state of data associated with 'ovb' */
+void
+ofputil_version_bitmap_init(struct ofputil_version_bitmap *ovb)
+{
+    const struct ofputil_version_bitmap x = OFPUTIL_VERSION_BITMAP_INITIALIZER;
+    memcpy(ovb, &x, sizeof x);
+}
+
+/* Free data associated with 'ovb' but not 'ovb' itself */
+void
+ofputil_version_bitmap_free_data(struct ofputil_version_bitmap *ovb)
+{
+    if (ovb->bitmap) {
+        free(ovb->bitmap);
+    }
+}
+
+/* Duplicate data associated with 'src' and store in 'dst' */
+void
+ofputil_version_bitmap_clone_data(const struct ofputil_version_bitmap *src,
+                                  struct ofputil_version_bitmap *dst)
+{
+    dst->n_bits = src->n_bits;
+    dst->bitmap = bitmap_clone(src->bitmap, src->n_bits);
+}
+
+/* Set the bit 'offset' in 'ovb' to one
+ * Expands bitmap as necessary */
+void
+ofputil_version_bitmap_set1(struct ofputil_version_bitmap *ovb, size_t offset)
+{
+    if (offset >= ovb->n_bits) {
+        struct ofputil_version_bitmap old = *ovb;
+
+        ovb->n_bits = offset + 1;
+        ovb->bitmap = bitmap_allocate(ovb->n_bits);
+        memcpy(ovb->bitmap, old.bitmap, old.n_bits);
+    }
+    bitmap_set1(ovb->bitmap, offset);
+}
+
+/* Set the bit offsets of 'ovb' from 0 to 'end', excluding 'end' itself to one
+ * Expands bitmap as necessary */
+void
+ofputil_version_bitmap_set_range1(struct ofputil_version_bitmap *ovb,
+                                  size_t start, size_t end)
+{
+    size_t i;
+
+    i = end - 1;
+    do {
+        ofputil_version_bitmap_set1(ovb, i);
+    } while (i-- > start);
+}
+
+/* Test if bit offset is set in ovb. */
+bool
+ofputil_version_bitmap_is_set(const struct ofputil_version_bitmap *ovb,
+                              size_t offset)
+{
+    if (offset >= ovb->n_bits) {
+        return false;
+    }
+    return bitmap_is_set(ovb->bitmap, offset);
+}
+
+/* Scans 'ovb'. Returns the bit offset of the highest-numbered bit set to 1,
+ * or 'ovb->n_bits' if all of the bits are set to 0. */
+size_t
+ofputil_version_bitmap_scanr(const struct ofputil_version_bitmap *ovb)
+{
+    return bitmap_scanr(ovb->bitmap, 0, ovb->n_bits);
+}
+
+/* Peform the bitwise and of 'a' and 'b', the result is stored in 'b' */
+void
+ofputil_version_bitmap_and(const struct ofputil_version_bitmap *a,
+                           struct ofputil_version_bitmap *b)
+{
+    /* XXX slow */
+    size_t e = MIN(a->n_bits, b->n_bits);
+    bitmap_and(a->bitmap, b->bitmap, 0, e);
+    while (e <  b->n_bits) {
+        bitmap_set0(b->bitmap, e++);
+    }
+}
+
+/* Find the number of bits in 'ovb' that are set to one. */
+size_t
+ofputil_version_bitmap_count_set(const struct ofputil_version_bitmap *ovb)
+{
+    size_t i, n = 0;
+
+    for (i = 0; i < ovb->n_bits; i++) {
+        if (bitmap_is_set(ovb->bitmap, i)) {
+            n++;
+        }
+    }
+
+    return n;
+}
+
+static void
+ofputil_format_version(struct ds *msg, size_t version)
+{
+    ds_put_format(msg, "0x%02zx", version);
+}
+
+static void
+ofputil_format_version_name(struct ds *msg, size_t version)
+{
+    ds_put_cstr(msg, ofputil_version_to_string(version));
+}
+
+static void
+ofputil_format_version_bitmap__(struct ds *msg,
+                                const struct ofputil_version_bitmap *ovb,
+                                void (*format_version)(struct ds *msg,
+                                                       size_t version))
+{
+    size_t i, max;
+
+    if (!ovb->bitmap) {
+        return;
+    }
+
+    max = ofputil_version_bitmap_scanr(ovb);
+    for (i = 0; i <= max; i++) {
+        if (bitmap_is_set(ovb->bitmap, i)) {
+            format_version(msg, i);
+            if (i != max) {
+                ds_put_cstr(msg, ", ");
+            }
+        }
+    }
+}
+
+void
+ofputil_format_version_bitmap(struct ds *msg,
+                              const struct ofputil_version_bitmap *ovb)
+{
+    ofputil_format_version_bitmap__(msg, ovb, ofputil_format_version);
+}
+
+void
+ofputil_format_version_bitmap_names(struct ds *msg,
+                                    const struct ofputil_version_bitmap *ovb)
+{
+    ofputil_format_version_bitmap__(msg, ovb, ofputil_format_version_name);
+}
+
+const struct ofputil_version_bitmap *
+ofputil_get_supported_versions(void)
+{
+    static struct ofputil_version_bitmap ovb =
+        OFPUTIL_VERSION_BITMAP_INITIALIZER;
+
+    if (!ovb.bitmap) {
+        ofputil_version_bitmap_set1(&ovb, OFP12_VERSION);
+        ofputil_version_bitmap_set1(&ovb, OFP10_VERSION);
+    }
+
+    return &ovb;
+}
+
+const struct ofputil_version_bitmap *
+ofputil_get_allowed_versions_default(void)
+{
+    static struct ofputil_version_bitmap ovb =
+        OFPUTIL_VERSION_BITMAP_INITIALIZER;
+
+    if (!ovb.bitmap) {
+        ofputil_version_bitmap_set1(&ovb, OFP10_VERSION);
+    }
+
+    return &ovb;
+}
+
 /* Returns an OpenFlow message that, sent on an OpenFlow connection whose
  * protocol is 'current', at least partly transitions the protocol to 'want'.
  * Stores in '*next' the protocol that will be in effect on the OpenFlow
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 2f73ec2..c7a6a07 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -98,6 +98,59 @@ char *ofputil_protocols_to_string(enum ofputil_protocol);
 enum ofputil_protocol ofputil_protocols_from_string(const char *);
 enum ofputil_protocol ofputil_usable_protocols(const struct match *);
 
+/* A bitmap of version numbers
+ *
+ * Bit offsets correspond to ofp_version numbers which in turn
+ * correspond to wire-protocol numbers for Open Flow versions..
+ * E.g. (1 << OFP10_VERSION) is the mask for Open Flow 1.1.
+ * If the bit for a version is set then it is allowed, otherwise it is
+ * disallowed. */
+
+struct ofputil_version_bitmap {
+    unsigned long *bitmap;
+    size_t n_bits;
+};
+
+#define OFPUTIL_VERSION_BITMAP_INITIALIZER { .bitmap = NULL, .n_bits = 0 }
+
+void ofputil_version_bitmap_init(struct ofputil_version_bitmap *ovb);
+void ofputil_version_bitmap_free_data(struct ofputil_version_bitmap *ovb);
+void ofputil_version_bitmap_clone_data(const struct ofputil_version_bitmap 
*src,
+                                       struct ofputil_version_bitmap *dst);
+void ofputil_version_bitmap_set1(struct ofputil_version_bitmap *ovb,
+                                 size_t offset);
+void ofputil_version_bitmap_set_range1(struct ofputil_version_bitmap *ovb,
+                                       size_t start, size_t end);
+bool ofputil_version_bitmap_is_set(const struct ofputil_version_bitmap *ovb,
+                                   size_t offset);
+size_t ofputil_version_bitmap_scanr(const struct ofputil_version_bitmap *ovb);
+void ofputil_version_bitmap_and(const struct ofputil_version_bitmap *a,
+                                struct ofputil_version_bitmap *b);
+size_t ofputil_version_bitmap_count_set(const struct ofputil_version_bitmap 
*ovb);
+
+void ofputil_format_version_bitmap(struct ds *msg,
+                                   const struct ofputil_version_bitmap *ovb);
+void ofputil_format_version_bitmap_names(struct ds *msg,
+                                         const struct ofputil_version_bitmap 
*ovb);
+
+const struct ofputil_version_bitmap *ofputil_get_supported_versions(void);
+const struct ofputil_version_bitmap 
*ofputil_get_allowed_versions_default(void);
+
+enum ofputil_protocol ofputil_protocols_from_string(const char *s);
+
+const char *ofputil_version_to_string(enum ofp_version ofp_version);
+void ofputil_versions_from_string(const char *s,
+                                  struct ofputil_version_bitmap *ovb);
+
+struct ofputil_hello {
+    enum ofp_version version;
+    struct ofputil_version_bitmap version_bitmap;
+};
+
+enum ofperr ofputil_decode_hello(struct ofputil_hello *hello,
+                                 struct ofpbuf *msg);
+struct ofpbuf *ofputil_encode_hello(const struct ofputil_version_bitmap *ovb);
+
 struct ofpbuf *ofputil_encode_set_protocol(enum ofputil_protocol current,
                                            enum ofputil_protocol want,
                                            enum ofputil_protocol *next);
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to