bundles: Reject bundle add with bad flags.
[cascardo/ovs.git] / ofproto / bundles.c
1 /*
2  * Copyright (c) 2013, 2014 Alexandru Copot <alex.mihai.c@gmail.com>, with support from IXIA.
3  * Copyright (c) 2013, 2014 Daniel Baluta <dbaluta@ixiacom.com>
4  * Copyright (c) 2014 Nicira, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <config.h>
20
21 #include "coverage.h"
22 #include "fail-open.h"
23 #include "in-band.h"
24 #include "odp-util.h"
25 #include "ofp-actions.h"
26 #include "ofp-msgs.h"
27 #include "ofp-util.h"
28 #include "ofpbuf.h"
29 #include "ofproto-provider.h"
30 #include "pinsched.h"
31 #include "poll-loop.h"
32 #include "pktbuf.h"
33 #include "rconn.h"
34 #include "shash.h"
35 #include "simap.h"
36 #include "stream.h"
37 #include "timeval.h"
38 #include "openvswitch/vconn.h"
39 #include "openvswitch/vlog.h"
40
41 #include "bundles.h"
42
43 VLOG_DEFINE_THIS_MODULE(bundles);
44
45 enum bundle_state {
46     BS_OPEN,
47     BS_CLOSED
48 };
49
50 struct ofp_bundle {
51     struct hmap_node  node;      /* In struct ofconn's "bundles" hmap. */
52     uint32_t          id;
53     uint16_t          flags;
54     enum bundle_state state;
55
56     /* List of 'struct bundle_message's */
57     struct ovs_list    msg_list;
58 };
59
60 struct bundle_message {
61     struct ofp_header *msg;
62     struct ovs_list   node;  /* Element in 'struct ofp_bundles's msg_list */
63 };
64
65 static uint32_t
66 bundle_hash(uint32_t id)
67 {
68     return hash_int(id, 0);
69 }
70
71 static struct ofp_bundle *
72 ofp_bundle_find(struct hmap *bundles, uint32_t id)
73 {
74     struct ofp_bundle *bundle;
75
76     HMAP_FOR_EACH_IN_BUCKET(bundle, node, bundle_hash(id), bundles) {
77         if (bundle->id == id) {
78             return bundle;
79         }
80     }
81
82     return NULL;
83 }
84
85 static struct ofp_bundle *
86 ofp_bundle_create(uint32_t id, uint16_t flags)
87 {
88     struct ofp_bundle *bundle;
89
90     bundle = xmalloc(sizeof(*bundle));
91
92     bundle->id = id;
93     bundle->flags = flags;
94
95     list_init(&bundle->msg_list);
96
97     return bundle;
98 }
99
100 static void
101 ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *item)
102 {
103     struct bundle_message *msg, *next;
104     struct hmap *bundles;
105
106     LIST_FOR_EACH_SAFE (msg, next, node, &item->msg_list) {
107         list_remove(&msg->node);
108         free(msg->msg);
109         free(msg);
110     }
111
112     bundles = ofconn_get_bundles(ofconn);
113     hmap_remove(bundles, &item->node);
114
115     free(item);
116 }
117
118 void
119 ofp_bundle_remove_all(struct ofconn *ofconn)
120 {
121     struct ofp_bundle *b, *next;
122     struct hmap *bundles;
123
124     bundles = ofconn_get_bundles(ofconn);
125
126     HMAP_FOR_EACH_SAFE (b, next, node, bundles) {
127         ofp_bundle_remove(ofconn, b);
128     }
129 }
130
131 enum ofperr
132 ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t flags)
133 {
134     struct hmap *bundles;
135     struct ofp_bundle *bundle;
136
137     bundles = ofconn_get_bundles(ofconn);
138     bundle = ofp_bundle_find(bundles, id);
139
140     if (bundle) {
141         VLOG_INFO("Bundle %x already exists.", id);
142         ofp_bundle_remove(ofconn, bundle);
143
144         return OFPERR_OFPBFC_BAD_ID;
145     }
146
147     /* XXX: Check the limit of open bundles */
148
149     bundle = ofp_bundle_create(id, flags);
150     bundle->state = BS_OPEN;
151
152     bundles = ofconn_get_bundles(ofconn);
153     hmap_insert(bundles, &bundle->node, bundle_hash(id));
154
155     return 0;
156 }
157
158 enum ofperr
159 ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t flags)
160 {
161     struct hmap *bundles;
162     struct ofp_bundle *bundle;
163
164     bundles = ofconn_get_bundles(ofconn);
165     bundle = ofp_bundle_find(bundles, id);
166
167     if (!bundle) {
168         return OFPERR_OFPBFC_BAD_ID;
169     }
170
171     if (bundle->state == BS_CLOSED) {
172         ofp_bundle_remove(ofconn, bundle);
173         return OFPERR_OFPBFC_BUNDLE_CLOSED;
174     }
175
176     if (bundle->flags != flags) {
177         ofp_bundle_remove(ofconn, bundle);
178         return OFPERR_OFPBFC_BAD_FLAGS;
179     }
180
181     bundle->state = BS_CLOSED;
182     return 0;
183 }
184
185 enum ofperr
186 ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
187 {
188     struct hmap *bundles;
189     struct ofp_bundle *bundle;
190
191     bundles = ofconn_get_bundles(ofconn);
192     bundle = ofp_bundle_find(bundles, id);
193
194     if (!bundle) {
195         return OFPERR_OFPBFC_BAD_ID;
196     }
197     if (bundle->flags != flags) {
198         ofp_bundle_remove(ofconn, bundle);
199         return OFPERR_OFPBFC_BAD_FLAGS;
200     }
201
202     /* XXX: actual commit */
203
204     return OFPERR_OFPBFC_MSG_UNSUP;
205 }
206
207 enum ofperr
208 ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
209 {
210     struct hmap *bundles;
211     struct ofp_bundle *bundle;
212
213     bundles = ofconn_get_bundles(ofconn);
214     bundle = ofp_bundle_find(bundles, id);
215
216     if (!bundle) {
217         return OFPERR_OFPBFC_BAD_ID;
218     }
219
220     ofp_bundle_remove(ofconn, bundle);
221
222     return 0;
223 }
224
225 enum ofperr
226 ofp_bundle_add_message(struct ofconn *ofconn, struct ofputil_bundle_add_msg *badd)
227 {
228     struct hmap *bundles;
229     struct ofp_bundle *bundle;
230     struct bundle_message *bmsg;
231
232     bundles = ofconn_get_bundles(ofconn);
233     bundle = ofp_bundle_find(bundles, badd->bundle_id);
234
235     if (!bundle) {
236         bundle = ofp_bundle_create(badd->bundle_id, badd->flags);
237         bundle->state = BS_OPEN;
238
239         bundles = ofconn_get_bundles(ofconn);
240         hmap_insert(bundles, &bundle->node, bundle_hash(badd->bundle_id));
241     } else if (bundle->state == BS_CLOSED) {
242         ofp_bundle_remove(ofconn, bundle);
243         return OFPERR_OFPBFC_BUNDLE_CLOSED;
244     } else if (badd->flags != bundle->flags) {
245         ofp_bundle_remove(ofconn, bundle);
246         return OFPERR_OFPBFC_BAD_FLAGS;
247     }
248
249     bmsg = xmalloc(sizeof *bmsg);
250     bmsg->msg = xmemdup(badd->msg, ntohs(badd->msg->length));
251     list_push_back(&bundle->msg_list, &bmsg->node);
252     return 0;
253 }