OpenFlow bundle messages should be decoded and validated at the time
they are added to the bundle.  This commit does this for flow mod and
port mod messages.

Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>
---
 lib/ofp-print.c   |    2 +-
 lib/ofp-util.c    |   10 +++++++---
 lib/ofp-util.h    |    5 ++++-
 ofproto/bundles.c |   34 +++++++++++++---------------------
 ofproto/bundles.h |   48 ++++++++++++++++++++++++++++++++++++++++--------
 ofproto/ofproto.c |   35 +++++++++++++++++++++++++++++++++--
 6 files changed, 98 insertions(+), 36 deletions(-)

diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index c446770..18ad4b4 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2620,7 +2620,7 @@ ofp_print_bundle_add(struct ds *s, const struct 
ofp_header *oh, int verbosity)
     struct ofputil_bundle_add_msg badd;
     char *msg;
 
-    error = ofputil_decode_bundle_add(oh, &badd);
+    error = ofputil_decode_bundle_add(oh, &badd, NULL);
     if (error) {
         ofp_print_error(s, error);
         return;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index bfccc69..844c64d 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -8575,7 +8575,8 @@ ofputil_is_bundlable(enum ofptype type)
 
 enum ofperr
 ofputil_decode_bundle_add(const struct ofp_header *oh,
-                          struct ofputil_bundle_add_msg *msg)
+                          struct ofputil_bundle_add_msg *msg,
+                          enum ofptype *type_ptr)
 {
     const struct ofp14_bundle_ctrl_msg *m;
     struct ofpbuf b;
@@ -8602,8 +8603,11 @@ ofputil_decode_bundle_add(const struct ofp_header *oh,
     }
 
     /* Reject unbundlable messages. */
-    error = ofptype_decode(&type, msg->msg);
-    if (error || !ofputil_is_bundlable(type)) {
+    if (!type_ptr) {
+        type_ptr = &type;
+    }
+    error = ofptype_decode(type_ptr, msg->msg);
+    if (error || !ofputil_is_bundlable(*type_ptr)) {
         return OFPERR_OFPBFC_MSG_UNSUP; /* 'error' could be confusing. */
     }
 
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 6fe2883..b486d3e 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -1093,6 +1093,8 @@ struct ofputil_bundle_add_msg {
     const struct ofp_header   *msg;
 };
 
+enum ofptype;
+
 enum ofperr ofputil_decode_bundle_ctrl(const struct ofp_header *,
                                        struct ofputil_bundle_ctrl_msg *);
 
@@ -1103,5 +1105,6 @@ struct ofpbuf *ofputil_encode_bundle_add(enum ofp_version 
ofp_version,
                                          struct ofputil_bundle_add_msg *msg);
 
 enum ofperr ofputil_decode_bundle_add(const struct ofp_header *,
-                                      struct ofputil_bundle_add_msg *);
+                                      struct ofputil_bundle_add_msg *,
+                                      enum ofptype *type);
 #endif /* ofp-util.h */
diff --git a/ofproto/bundles.c b/ofproto/bundles.c
index 4184a33..1d57190 100644
--- a/ofproto/bundles.c
+++ b/ofproto/bundles.c
@@ -57,11 +57,6 @@ struct ofp_bundle {
     struct list       msg_list;
 };
 
-struct bundle_message {
-    struct ofp_header *msg;
-    struct list       node;  /* Element in 'struct ofp_bundles's msg_list */
-};
-
 static uint32_t
 bundle_hash(uint32_t id)
 {
@@ -98,21 +93,20 @@ ofp_bundle_create(uint32_t id, uint16_t flags)
 }
 
 static void
-ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *item)
+ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *bundle)
 {
-    struct bundle_message *msg, *next;
+    struct ofp_bundle_entry *msg, *next;
     struct hmap *bundles;
 
-    LIST_FOR_EACH_SAFE (msg, next, node, &item->msg_list) {
+    LIST_FOR_EACH_SAFE (msg, next, node, &bundle->msg_list) {
         list_remove(&msg->node);
-        free(msg->msg);
-        free(msg);
+        ofp_bundle_entry_free(msg);
     }
 
     bundles = ofconn_get_bundles(ofconn);
-    hmap_remove(bundles, &item->node);
+    hmap_remove(bundles, &bundle->node);
 
-    free(item);
+    free(bundle);
 }
 
 void
@@ -188,7 +182,7 @@ ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, 
uint16_t flags)
     struct hmap *bundles;
     struct ofp_bundle *bundle;
     enum ofperr error = 0;
-    struct bundle_message *msg;
+    struct ofp_bundle_entry *msg;
 
     bundles = ofconn_get_bundles(ofconn);
     bundle = ofp_bundle_find(bundles, id);
@@ -228,31 +222,29 @@ ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
 }
 
 enum ofperr
-ofp_bundle_add_message(struct ofconn *ofconn, struct ofputil_bundle_add_msg 
*badd)
+ofp_bundle_add_message(struct ofconn *ofconn, uint32_t id, uint16_t flags,
+                       struct ofp_bundle_entry *bmsg)
 {
     struct hmap *bundles;
     struct ofp_bundle *bundle;
-    struct bundle_message *bmsg;
 
     bundles = ofconn_get_bundles(ofconn);
-    bundle = ofp_bundle_find(bundles, badd->bundle_id);
+    bundle = ofp_bundle_find(bundles, id);
 
     if (!bundle) {
-        bundle = ofp_bundle_create(badd->bundle_id, badd->flags);
+        bundle = ofp_bundle_create(id, flags);
         bundle->state = BS_OPEN;
 
         bundles = ofconn_get_bundles(ofconn);
-        hmap_insert(bundles, &bundle->node, bundle_hash(badd->bundle_id));
+        hmap_insert(bundles, &bundle->node, bundle_hash(id));
     } else if (bundle->state == BS_CLOSED) {
         ofp_bundle_remove(ofconn, bundle);
         return OFPERR_OFPBFC_BUNDLE_CLOSED;
-    } else if (badd->flags != bundle->flags) {
+    } else if (flags != bundle->flags) {
         ofp_bundle_remove(ofconn, bundle);
         return OFPERR_OFPBFC_BAD_FLAGS;
     }
 
-    bmsg = xmalloc(sizeof *bmsg);
-    bmsg->msg = xmemdup(badd->msg, ntohs(badd->msg->length));
     list_push_back(&bundle->msg_list, &bmsg->node);
     return 0;
 }
diff --git a/ofproto/bundles.h b/ofproto/bundles.h
index 9a6dfa5..ecd068b 100644
--- a/ofproto/bundles.h
+++ b/ofproto/bundles.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2013, 2014 Alexandru Copot <alex.miha...@gmail.com>, with 
support from IXIA.
  * Copyright (c) 2013, 2014 Daniel Baluta <dbal...@ixiacom.com>
+ * Copyright (c) 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,19 +29,50 @@
 extern "C" {
 #endif
 
+struct ofp_bundle_entry {
+    struct list       node;
+    ovs_be32          xid;   /* For error returns. */
+    enum ofptype      type;
+    union {
+        struct ofputil_flow_mod fm;
+        struct ofputil_port_mod pm;
+    };
+    struct ofpbuf ofpacts;
+    uint64_t ofpacts_stub[1024 / 8];
+};
 
-enum ofperr ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t 
flags);
+static inline struct ofp_bundle_entry *ofp_bundle_entry_alloc(
+    enum ofptype type, ovs_be32 xid);
+static inline void ofp_bundle_entry_free(struct ofp_bundle_entry *);
 
-enum ofperr ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t 
flags);
+enum ofperr ofp_bundle_open(struct ofconn *, uint32_t id, uint16_t flags);
+enum ofperr ofp_bundle_close(struct ofconn *, uint32_t id, uint16_t flags);
+enum ofperr ofp_bundle_commit(struct ofconn *, uint32_t id, uint16_t flags);
+enum ofperr ofp_bundle_discard(struct ofconn *, uint32_t id);
+enum ofperr ofp_bundle_add_message(struct ofconn *, uint32_t id,
+                                   uint16_t flags, struct ofp_bundle_entry *);
+void ofp_bundle_remove_all(struct ofconn *);
+
+static inline struct ofp_bundle_entry *
+ofp_bundle_entry_alloc(enum ofptype type, ovs_be32 xid)
+{
+    struct ofp_bundle_entry *entry = xmalloc(sizeof *entry);
 
-enum ofperr ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t 
flags);
+    ofpbuf_use_stub(&entry->ofpacts, entry->ofpacts_stub,
+                    sizeof entry->ofpacts_stub);
+    entry->xid = xid;
+    entry->type = type;
 
-enum ofperr ofp_bundle_discard(struct ofconn *ofconn, uint32_t id);
-
-enum ofperr ofp_bundle_add_message(struct ofconn *ofconn,
-                                   struct ofputil_bundle_add_msg *badd);
+    return entry;
+}
 
-void ofp_bundle_remove_all(struct ofconn *ofconn);
+static inline void ofp_bundle_entry_free(struct ofp_bundle_entry *entry)
+{
+    if (entry) {
+        ofpbuf_uninit(&entry->ofpacts);
+        free(entry);
+    }
+}
 
 #ifdef  __cplusplus
 }
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 44d36d5..10af5bf 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -6175,20 +6175,51 @@ handle_bundle_control(struct ofconn *ofconn, const 
struct ofp_header *oh)
 static enum ofperr
 handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
 {
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     enum ofperr error;
     struct ofputil_bundle_add_msg badd;
+    struct ofp_bundle_entry *bmsg;
+    enum ofptype type;
 
     error = reject_slave_controller(ofconn);
     if (error) {
         return error;
     }
 
-    error = ofputil_decode_bundle_add(oh, &badd);
+    error = ofputil_decode_bundle_add(oh, &badd, &type);
     if (error) {
         return error;
     }
 
-    return ofp_bundle_add_message(ofconn, &badd);
+    bmsg = ofp_bundle_entry_alloc(type, badd.msg->xid);
+
+    if (type == OFPTYPE_PORT_MOD) {
+        error = ofputil_decode_port_mod(badd.msg, &bmsg->pm, false);
+    } else if (type == OFPTYPE_FLOW_MOD) {
+        error = ofputil_decode_flow_mod(&bmsg->fm, badd.msg,
+                                        ofconn_get_protocol(ofconn),
+                                        &bmsg->ofpacts,
+                                        u16_to_ofp(ofproto->max_ports),
+                                        ofproto->n_tables);
+    } else {
+        OVS_NOT_REACHED();
+    }
+
+    if (!error && ofpbuf_size(&bmsg->ofpacts)) {
+        error = ofproto_check_ofpacts(ofproto, ofpbuf_data(&bmsg->ofpacts),
+                                      ofpbuf_size(&bmsg->ofpacts));
+    }
+
+    if (!error) {
+        error = ofp_bundle_add_message(ofconn, badd.bundle_id, badd.flags,
+                                       bmsg);
+    }
+
+    if (error) {
+        ofp_bundle_entry_free(bmsg);
+    }
+
+    return error;
 }
 
 static enum ofperr
-- 
1.7.10.4

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

Reply via email to