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