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