[ovs-dev] [PATCH] groups: Add 'ofpbucket' abstraction to ofp-actions library
Casey Barker
crbarker at google.com
Fri Aug 9 23:09:19 UTC 2013
This is some early infrastructure towards support for Openflow forwarding
groups as introduced in the 1.1 spec.
The ofpbucket structure is an internal representation of a group bucket and
holds a list of ofpacts. This patch includes management functions for
parsing/packing buckets in Openflow and managing collections of buckets.
This code has been tested as part of a working implementation of groups, and
unit tested in a downstream harness, but lacks unit tests in the OVS
harness.
Signed-off-by: Casey Barker <crbarker at google.com>
---
Ben: Please feel free to accept or reject this, depending on how it fits
your plans for groups. In my implementation, this structure ends up passing
through the ofproto-provider API.
Patch attached to prevent gmail from eating it.
lib/ofp-actions.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/ofp-actions.h | 61 +++++++++++++
2 files changed, 303 insertions(+)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openvswitch.org/pipermail/ovs-dev/attachments/20130809/4e69ca17/attachment-0003.html>
-------------- next part --------------
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 61e2854..b1d68fa 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -2474,3 +2474,245 @@ ofpact_set_field_init(struct ofpact_reg_load *load, const struct mf_field *mf,
bitwise_copy(src, mf->n_bytes, load->dst.ofs,
&load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
}
+
+/* Converting OpenFlow to ofpbuckets. */
+
+static enum ofperr
+ofpbucket_from_openflow11(const struct ofp11_bucket *b,
+ struct ofpbuf *ofpbuckets)
+{
+ enum ofperr error;
+ struct ofpbuf ofpacts;
+ struct ofpbuf openflow_actions;
+ size_t actions_len = ntohs(b->len) - sizeof(*b);
+
+ struct ofpbucket *ofpbucket = ofpbucket_put(ofpbuckets);
+ ofpbucket->weight = ntohs(b->weight);
+ ofpbucket->watch_port = ntohl(b->watch_port);
+ ofpbucket->watch_group = ntohl(b->watch_group);
+
+ ofpbuf_init(&ofpacts, 64);
+ ofpbuf_use_const(&openflow_actions, b+1, actions_len);
+ error = ofpacts_pull_actions(&openflow_actions, actions_len, &ofpacts,
+ ofpacts_from_openflow11);
+
+ ofpbucket->ofpacts_len = ofpacts.size;
+ ofpbucket->ofpacts = ofpbuf_steal_data(&ofpacts);
+ return error;
+}
+
+static inline struct ofp11_bucket *
+bucket11_next(const struct ofp11_bucket *b)
+{
+ return (struct ofp11_bucket *) (void *) ((uint8_t *) b + ntohs(b->len));
+}
+
+static inline bool
+bucket11_is_valid(const struct ofp11_bucket *b, size_t buckets_len)
+{
+ uint16_t len;
+ if (buckets_len < sizeof *b) return false;
+ len = ntohs(b->len);
+ return (len >= sizeof *b && len <= buckets_len);
+}
+
+static void
+log_bad_bucket11(const struct ofp11_bucket *buckets, size_t buckets_len,
+ size_t ofs, enum ofperr error)
+{
+ if (!VLOG_DROP_WARN(&rl)) {
+ struct ds s;
+
+ ds_init(&s);
+ ds_put_hex_dump(&s, buckets, buckets_len, 0, false);
+ VLOG_WARN("bad bucket at offset %#zx (%s):\n%s",
+ ofs, ofperr_get_name(error), ds_cstr(&s));
+ ds_destroy(&s);
+ }
+}
+
+static enum ofperr
+ofpbuckets_from_openflow11(const void *openflow_buckets,
+ size_t buckets_len,
+ struct ofpbuf *ofpbuckets)
+{
+ const struct ofp11_bucket *buckets = openflow_buckets;
+ const struct ofp11_bucket *b;
+ size_t left;
+ enum ofperr error;
+
+ ofpbuf_clear(ofpbuckets);
+ for (b = buckets, left = buckets_len;
+ left > 0 && bucket11_is_valid(b, left);
+ left -= ntohs(b->len), b = bucket11_next(b)) {
+ error = ofpbucket_from_openflow11(b, ofpbuckets);
+ if (error) {
+ log_bad_bucket11(buckets, buckets_len, b - buckets, error);
+ return error;
+ }
+ }
+ if (left) {
+ error = OFPERR_OFPBAC_BAD_LEN;
+ log_bad_bucket11(buckets, buckets_len, b - buckets, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static enum ofperr
+ofpbuckets_pull_openflow(struct ofpbuf *openflow,
+ size_t buckets_len,
+ struct ofpbucket **ofpbuckets,
+ size_t *n_ofpbuckets,
+ enum ofperr(*parser)(const void *openflow_buckets,
+ size_t buckets_len,
+ struct ofpbuf *ofpbuckets))
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ struct ofp11_bucket *buckets;
+ struct ofpbuf buffer;
+ enum ofperr error;
+
+ buckets = ofpbuf_try_pull(openflow, buckets_len);
+ if (buckets == NULL) {
+ VLOG_WARN_RL(&rl, "OpenFlow message buckets length %zu exceeds "
+ "remaining message length (%zu)",
+ buckets_len, openflow->size);
+ *ofpbuckets = NULL;
+ *n_ofpbuckets = 0;
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ ofpbuf_init(&buffer, 64);
+ error = parser(buckets, buckets_len, &buffer);
+ *n_ofpbuckets = buffer.size / sizeof **ofpbuckets;
+ *ofpbuckets = ofpbuf_steal_data(&buffer);
+
+ if (error) {
+ ofpbucket_free(*ofpbuckets, *n_ofpbuckets);
+ *ofpbuckets = NULL;
+ *n_ofpbuckets = 0;
+ }
+ return error;
+}
+
+/* This call attempts to convert 'buckets_len' bytes of OpenFlow 1.1 buckets
+ * from the front of 'openflow' into ofpbuckets. On success, it returns a
+ * buffer containing 'n_ofpbuckets' at '*ofpbuckets', and the caller owns the
+ * buckets and attached actions; on failure, it sets n_ofpbuckets to zero and
+ * *ofpbuckets to null. It returns 0 if successful, otherwise an OpenFlow
+ * error. */
+enum ofperr
+ofpbuckets_pull_openflow11(struct ofpbuf *openflow,
+ size_t buckets_len,
+ struct ofpbucket **ofpbuckets,
+ size_t *n_ofpbuckets)
+{
+ return ofpbuckets_pull_openflow(openflow,
+ buckets_len,
+ ofpbuckets,
+ n_ofpbuckets,
+ ofpbuckets_from_openflow11);
+}
+
+/* Converting ofpbuckets to OpenFlow. */
+
+static void
+ofpbucket_to_openflow11(const struct ofpbucket *b, struct ofpbuf *openflow)
+{
+ struct ofp11_bucket *ofb;
+ ofb = openflow->l3 = ofpbuf_put_zeros(openflow, sizeof *ofb);
+ ofb->weight = htons(b->weight);
+ ofb->watch_port = htonl(b->watch_port);
+ ofb->watch_group = htonl(b->watch_group);
+ ofpacts_put_openflow11_actions(b->ofpacts, b->ofpacts_len, openflow);
+
+ /* Inserting actions may have rebuffered the buckets. */
+ ofb = openflow->l3;
+ ofb->len = htons((uint8_t *)ofpbuf_tail(openflow) - (uint8_t *)ofb);
+}
+
+/* Converts the 'n_ofpbuckets' ofpbuckets in 'ofpbuckets' into
+ * OpenFlow 1.1 buckets, appending the buckets to any existing
+ * data in 'openflow'. */
+void
+ofpbuckets_put_openflow11(const struct ofpbucket ofpbuckets[],
+ size_t n_ofpbuckets,
+ struct ofpbuf *openflow)
+{
+ const struct ofpbucket *b;
+
+ OFPBUCKET_FOR_EACH (b, ofpbuckets, n_ofpbuckets) {
+ ofpbucket_to_openflow11(b, openflow);
+ }
+}
+
+void
+ofpbuckets_format(const struct ofpbucket *ofpbuckets,
+ size_t n_ofpbuckets,
+ struct ds *s)
+{
+ const struct ofpbucket *ofpbucket;
+ int i = 0;
+ OFPBUCKET_FOR_EACH (ofpbucket, ofpbuckets, n_ofpbuckets) {
+ ds_put_format(s, "bucket %d: ", i);
+ if(ofpbucket->weight) {
+ ds_put_format(s, "weight=%d,", ofpbucket->weight);
+ }
+ if(ofpbucket->watch_port) {
+ ds_put_format(s, "watch_port=%d,", ofpbucket->watch_port);
+ }
+ if(ofpbucket->watch_group) {
+ ds_put_format(s, "watch_group=%d,", ofpbucket->watch_group);
+ }
+ ofpacts_format(ofpbucket->ofpacts, ofpbucket->ofpacts_len, s);
+ ds_put_char(s, '\n');
+ i++;
+ }
+}
+
+struct ofpbucket *
+ofpbucket_put(struct ofpbuf *ofpbuckets)
+{
+ return ofpbuf_put_zeros(ofpbuckets, sizeof (struct ofpbucket));
+}
+
+void
+ofpbucket_pull(struct ofpbuf *buffer,
+ struct ofpbucket **ofpbuckets,
+ size_t *n_ofpbuckets)
+{
+ *n_ofpbuckets = buffer->size / sizeof **ofpbuckets;
+ *ofpbuckets = ofpbuf_steal_data(buffer);
+}
+
+struct ofpbucket *
+ofpbucket_clone(struct ofpbucket* ofpbuckets, size_t n_ofpbuckets) {
+ struct ofpbucket *old, *new, *clone;
+ size_t len = sizeof *clone * n_ofpbuckets;
+
+ clone = new = xmalloc(len);
+ memcpy(clone, ofpbuckets, len);
+
+ OFPBUCKET_FOR_EACH (old, ofpbuckets, n_ofpbuckets) {
+ new->ofpacts = xmalloc(old->ofpacts_len);
+ memcpy(new->ofpacts, old->ofpacts, old->ofpacts_len);
+ new++;
+ }
+ return clone;
+}
+
+void
+ofpbucket_free(struct ofpbucket* ofpbuckets, size_t n_ofpbuckets)
+{
+ struct ofpbucket *ofpbucket;
+ OFPBUCKET_FOR_EACH (ofpbucket, ofpbuckets, n_ofpbuckets) {
+ if(ofpbucket->ofpacts) {
+ free(ofpbucket->ofpacts);
+ ofpbucket->ofpacts = NULL;
+ }
+ ofpbucket->ofpacts_len = 0;
+ }
+ free(ofpbuckets);
+}
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index ca33ca8..0d0d7e6 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -25,6 +25,10 @@
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* List of OVS abstracted actions.
*
* This macro is used directly only internally by this header, but the list is
@@ -654,4 +658,61 @@ enum ovs_instruction_type ovs_instruction_type_from_ofpact_type(
void ofpact_set_field_init(struct ofpact_reg_load *load,
const struct mf_field *mf, const void *src);
+/* Structure of an action bucket.
+ *
+ * Each bucket owns a collection of struct ofpacts representing one
+ * set of Openflow actions for a group. The owner of the bucket also
+ * owns the attached ofpacts and must free them if necessary.
+ */
+struct ofpbucket {
+ uint16_t weight; /* Relative weight for select groups. */
+ uint32_t watch_port; /* Port whose state determines whether this
+ * bucket is alive for fast-failover. */
+ uint32_t watch_group; /* Group whose state determines whether this
+ * bucket is alive for fast-failover. */
+ struct ofpact *ofpacts; /* Actions associated with this bucket. */
+ size_t ofpacts_len; /* Length of the actions. */
+};
+
+#define OFPBUCKET_FOR_EACH(POS, OFPBUCKETS, N_OFPBUCKETS) \
+ for ((POS) = (OFPBUCKETS); (POS) < ((OFPBUCKETS) + (N_OFPBUCKETS)); \
+ (POS) = (POS) + 1)
+
+/* Converting OpenFlow to ofpbuckets. */
+enum ofperr ofpbuckets_pull_openflow11(struct ofpbuf *openflow,
+ size_t buckets_len,
+ struct ofpbucket **ofpbuckets,
+ size_t *n_ofpbuckets);
+
+/* Converting ofpbuckets to OpenFlow. */
+void ofpbuckets_put_openflow11(const struct ofpbucket ofpbuckets[],
+ size_t n_ofpbuckets,
+ struct ofpbuf *openflow);
+
+/* Formatting ofpbuckets. */
+void ofpbuckets_format(const struct ofpbucket *,
+ size_t n_ofpbuckets,
+ struct ds *s);
+
+/* Appends a new 'ofpbucket' to 'ofpbuckets' initializing fields to zero. */
+struct ofpbucket *ofpbucket_put(struct ofpbuf *ofpbuckets);
+
+/* Steals the data from 'buffer' and assigns it to 'ofpbuckets', computing
+ * 'n_ofpbuckets'. */
+void ofpbucket_pull(struct ofpbuf *buffer,
+ struct ofpbucket **ofpbuckets,
+ size_t *n_ofpbuckets);
+
+/* Clones ofpbuckets including all actions and returns a pointer to the
+ * clone. */
+struct ofpbucket *ofpbucket_clone(struct ofpbucket* ofpbuckets,
+ size_t n_ofpbuckets);
+
+/* Frees 'ofpbuckets->ofpacts' for all buckets in the array. */
+void ofpbucket_free(struct ofpbucket* ofpbuckets, size_t n_ofpbuckets);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ofp-actions.h */
More information about the dev
mailing list