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