Revert "ovs-ofctl: Always prints recirc_id in decimal"
[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;
104     struct hmap *bundles;
105
106     LIST_FOR_EACH_POP (msg, node, &item->msg_list) {
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     /* XXX: 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     enum ofperr error = 0;
190     struct bundle_message *msg;
191
192     bundles = ofconn_get_bundles(ofconn);
193     bundle = ofp_bundle_find(bundles, id);
194
195     if (!bundle) {
196         return OFPERR_OFPBFC_BAD_ID;
197     }
198     if (bundle->flags != flags) {
199         error = OFPERR_OFPBFC_BAD_FLAGS;
200     } else {
201         LIST_FOR_EACH (msg, node, &bundle->msg_list) {
202             /* XXX: actual commit */
203             error = OFPERR_OFPBFC_MSG_FAILED;
204         }
205     }
206
207     ofp_bundle_remove(ofconn, bundle);
208     return error;
209 }
210
211 enum ofperr
212 ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
213 {
214     struct hmap *bundles;
215     struct ofp_bundle *bundle;
216
217     bundles = ofconn_get_bundles(ofconn);
218     bundle = ofp_bundle_find(bundles, id);
219
220     if (!bundle) {
221         return OFPERR_OFPBFC_BAD_ID;
222     }
223
224     ofp_bundle_remove(ofconn, bundle);
225
226     return 0;
227 }
228
229 enum ofperr
230 ofp_bundle_add_message(struct ofconn *ofconn, struct ofputil_bundle_add_msg *badd)
231 {
232     struct hmap *bundles;
233     struct ofp_bundle *bundle;
234     struct bundle_message *bmsg;
235
236     bundles = ofconn_get_bundles(ofconn);
237     bundle = ofp_bundle_find(bundles, badd->bundle_id);
238
239     if (!bundle) {
240         bundle = ofp_bundle_create(badd->bundle_id, badd->flags);
241         bundle->state = BS_OPEN;
242
243         bundles = ofconn_get_bundles(ofconn);
244         hmap_insert(bundles, &bundle->node, bundle_hash(badd->bundle_id));
245     } else if (bundle->state == BS_CLOSED) {
246         ofp_bundle_remove(ofconn, bundle);
247         return OFPERR_OFPBFC_BUNDLE_CLOSED;
248     } else if (badd->flags != bundle->flags) {
249         ofp_bundle_remove(ofconn, bundle);
250         return OFPERR_OFPBFC_BAD_FLAGS;
251     }
252
253     bmsg = xmalloc(sizeof *bmsg);
254     bmsg->msg = xmemdup(badd->msg, ntohs(badd->msg->length));
255     list_push_back(&bundle->msg_list, &bmsg->node);
256     return 0;
257 }