]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-bundle.c
flow, match, classifier: Add new functions for miniflow and minimatch.
[mirror_ovs.git] / lib / ofp-bundle.c
CommitLineData
0d71302e
BP
1/*
2 * Copyright (c) 2008-2017 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18#include "openvswitch/ofp-bundle.h"
19#include <errno.h>
20#include <stdlib.h>
21#include "openvswitch/ofp-parse.h"
22#include "openvswitch/ofpbuf.h"
23#include "openvswitch/vlog.h"
24#include "util.h"
25
26VLOG_DEFINE_THIS_MODULE(ofp_bundle);
27
28/* Destroys 'bms'. */
29void
30ofputil_free_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms)
31{
32 for (size_t i = 0; i < n_bms; i++) {
33 switch ((int)bms[i].type) {
34 case OFPTYPE_FLOW_MOD:
35 free(CONST_CAST(struct ofpact *, bms[i].fm.ofpacts));
36 break;
37 case OFPTYPE_GROUP_MOD:
38 ofputil_uninit_group_mod(&bms[i].gm);
39 break;
40 case OFPTYPE_PACKET_OUT:
41 free(bms[i].po.ofpacts);
42 free(CONST_CAST(void *, bms[i].po.packet));
43 break;
44 default:
45 break;
46 }
47 }
48 free(bms);
49}
50
51void
52ofputil_encode_bundle_msgs(const struct ofputil_bundle_msg *bms,
53 size_t n_bms, struct ovs_list *requests,
54 enum ofputil_protocol protocol)
55{
56 enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
57
58 for (size_t i = 0; i < n_bms; i++) {
59 struct ofpbuf *request = NULL;
60
61 switch ((int)bms[i].type) {
62 case OFPTYPE_FLOW_MOD:
63 request = ofputil_encode_flow_mod(&bms[i].fm, protocol);
64 break;
65 case OFPTYPE_GROUP_MOD:
66 request = ofputil_encode_group_mod(version, &bms[i].gm);
67 break;
68 case OFPTYPE_PACKET_OUT:
69 request = ofputil_encode_packet_out(&bms[i].po, protocol);
70 break;
71 default:
72 break;
73 }
74 if (request) {
75 ovs_list_push_back(requests, &request->list_node);
76 }
77 }
78}
79
80enum ofperr
81ofputil_decode_bundle_ctrl(const struct ofp_header *oh,
82 struct ofputil_bundle_ctrl_msg *msg)
83{
84 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
85 enum ofpraw raw = ofpraw_pull_assert(&b);
86 ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_CONTROL
87 || raw == OFPRAW_ONFT13_BUNDLE_CONTROL);
88
89 const struct ofp14_bundle_ctrl_msg *m = b.msg;
90 msg->bundle_id = ntohl(m->bundle_id);
91 msg->type = ntohs(m->type);
92 msg->flags = ntohs(m->flags);
93
94 return 0;
95}
96
97struct ofpbuf *
98ofputil_encode_bundle_ctrl_request(enum ofp_version ofp_version,
99 struct ofputil_bundle_ctrl_msg *bc)
100{
101 struct ofpbuf *request;
102 struct ofp14_bundle_ctrl_msg *m;
103
104 switch (ofp_version) {
105 case OFP10_VERSION:
106 case OFP11_VERSION:
107 case OFP12_VERSION:
108 ovs_fatal(0, "bundles need OpenFlow 1.3 or later "
109 "(\'-O OpenFlow14\')");
110 case OFP13_VERSION:
111 case OFP14_VERSION:
112 case OFP15_VERSION:
113 case OFP16_VERSION:
114 request = ofpraw_alloc(ofp_version == OFP13_VERSION
115 ? OFPRAW_ONFT13_BUNDLE_CONTROL
116 : OFPRAW_OFPT14_BUNDLE_CONTROL, ofp_version, 0);
117 m = ofpbuf_put_zeros(request, sizeof *m);
118
119 m->bundle_id = htonl(bc->bundle_id);
120 m->type = htons(bc->type);
121 m->flags = htons(bc->flags);
122 break;
123 default:
124 OVS_NOT_REACHED();
125 }
126
127 return request;
128}
129
130struct ofpbuf *
131ofputil_encode_bundle_ctrl_reply(const struct ofp_header *oh,
132 struct ofputil_bundle_ctrl_msg *msg)
133{
134 struct ofpbuf *buf;
135 struct ofp14_bundle_ctrl_msg *m;
136
137 buf = ofpraw_alloc_reply(oh->version == OFP13_VERSION
138 ? OFPRAW_ONFT13_BUNDLE_CONTROL
139 : OFPRAW_OFPT14_BUNDLE_CONTROL, oh, 0);
140 m = ofpbuf_put_zeros(buf, sizeof *m);
141
142 m->bundle_id = htonl(msg->bundle_id);
143 m->type = htons(msg->type);
144 m->flags = htons(msg->flags);
145
146 return buf;
147}
148
149/* Return true for bundlable state change requests, false for other messages.
150 */
151static bool
152ofputil_is_bundlable(enum ofptype type)
153{
154 switch (type) {
155 /* Minimum required by OpenFlow 1.4. */
156 case OFPTYPE_PORT_MOD:
157 case OFPTYPE_FLOW_MOD:
158 /* Other supported types. */
159 case OFPTYPE_GROUP_MOD:
160 case OFPTYPE_PACKET_OUT:
161 return true;
162
163 /* Nice to have later. */
164 case OFPTYPE_FLOW_MOD_TABLE_ID:
165 case OFPTYPE_TABLE_MOD:
166 case OFPTYPE_METER_MOD:
167 case OFPTYPE_NXT_TLV_TABLE_MOD:
168
169 /* Not to be bundlable. */
170 case OFPTYPE_ECHO_REQUEST:
171 case OFPTYPE_FEATURES_REQUEST:
172 case OFPTYPE_GET_CONFIG_REQUEST:
173 case OFPTYPE_SET_CONFIG:
174 case OFPTYPE_BARRIER_REQUEST:
175 case OFPTYPE_ROLE_REQUEST:
176 case OFPTYPE_ECHO_REPLY:
177 case OFPTYPE_SET_FLOW_FORMAT:
178 case OFPTYPE_SET_PACKET_IN_FORMAT:
179 case OFPTYPE_SET_CONTROLLER_ID:
180 case OFPTYPE_FLOW_AGE:
181 case OFPTYPE_FLOW_MONITOR_CANCEL:
182 case OFPTYPE_SET_ASYNC_CONFIG:
183 case OFPTYPE_GET_ASYNC_REQUEST:
184 case OFPTYPE_DESC_STATS_REQUEST:
185 case OFPTYPE_FLOW_STATS_REQUEST:
186 case OFPTYPE_AGGREGATE_STATS_REQUEST:
187 case OFPTYPE_TABLE_STATS_REQUEST:
188 case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
189 case OFPTYPE_TABLE_DESC_REQUEST:
190 case OFPTYPE_PORT_STATS_REQUEST:
191 case OFPTYPE_QUEUE_STATS_REQUEST:
192 case OFPTYPE_PORT_DESC_STATS_REQUEST:
193 case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
194 case OFPTYPE_METER_STATS_REQUEST:
195 case OFPTYPE_METER_CONFIG_STATS_REQUEST:
196 case OFPTYPE_METER_FEATURES_STATS_REQUEST:
197 case OFPTYPE_GROUP_STATS_REQUEST:
198 case OFPTYPE_GROUP_DESC_STATS_REQUEST:
199 case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
200 case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
201 case OFPTYPE_BUNDLE_CONTROL:
202 case OFPTYPE_BUNDLE_ADD_MESSAGE:
203 case OFPTYPE_HELLO:
204 case OFPTYPE_ERROR:
205 case OFPTYPE_FEATURES_REPLY:
206 case OFPTYPE_GET_CONFIG_REPLY:
207 case OFPTYPE_PACKET_IN:
208 case OFPTYPE_FLOW_REMOVED:
209 case OFPTYPE_PORT_STATUS:
210 case OFPTYPE_BARRIER_REPLY:
211 case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
212 case OFPTYPE_DESC_STATS_REPLY:
213 case OFPTYPE_FLOW_STATS_REPLY:
214 case OFPTYPE_QUEUE_STATS_REPLY:
215 case OFPTYPE_PORT_STATS_REPLY:
216 case OFPTYPE_TABLE_STATS_REPLY:
217 case OFPTYPE_AGGREGATE_STATS_REPLY:
218 case OFPTYPE_PORT_DESC_STATS_REPLY:
219 case OFPTYPE_ROLE_REPLY:
220 case OFPTYPE_FLOW_MONITOR_PAUSED:
221 case OFPTYPE_FLOW_MONITOR_RESUMED:
222 case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
223 case OFPTYPE_GET_ASYNC_REPLY:
224 case OFPTYPE_GROUP_STATS_REPLY:
225 case OFPTYPE_GROUP_DESC_STATS_REPLY:
226 case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
227 case OFPTYPE_METER_STATS_REPLY:
228 case OFPTYPE_METER_CONFIG_STATS_REPLY:
229 case OFPTYPE_METER_FEATURES_STATS_REPLY:
230 case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
231 case OFPTYPE_TABLE_DESC_REPLY:
232 case OFPTYPE_ROLE_STATUS:
233 case OFPTYPE_REQUESTFORWARD:
234 case OFPTYPE_TABLE_STATUS:
235 case OFPTYPE_NXT_TLV_TABLE_REQUEST:
236 case OFPTYPE_NXT_TLV_TABLE_REPLY:
237 case OFPTYPE_NXT_RESUME:
238 case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
239 case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
240 case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
241 case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
242 case OFPTYPE_CT_FLUSH_ZONE:
243 break;
244 }
245
246 return false;
247}
248
249enum ofperr
250ofputil_decode_bundle_add(const struct ofp_header *oh,
251 struct ofputil_bundle_add_msg *msg,
252 enum ofptype *typep)
253{
254 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
255
256 /* Pull the outer ofp_header. */
257 enum ofpraw raw = ofpraw_pull_assert(&b);
258 ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE
259 || raw == OFPRAW_ONFT13_BUNDLE_ADD_MESSAGE);
260
261 /* Pull the bundle_ctrl header. */
262 const struct ofp14_bundle_ctrl_msg *m = ofpbuf_pull(&b, sizeof *m);
263 msg->bundle_id = ntohl(m->bundle_id);
264 msg->flags = ntohs(m->flags);
265
266 /* Pull the inner ofp_header. */
267 if (b.size < sizeof(struct ofp_header)) {
268 return OFPERR_OFPBFC_MSG_BAD_LEN;
269 }
270 msg->msg = b.data;
271 if (msg->msg->version != oh->version) {
272 return OFPERR_OFPBFC_BAD_VERSION;
273 }
274 size_t inner_len = ntohs(msg->msg->length);
275 if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) {
276 return OFPERR_OFPBFC_MSG_BAD_LEN;
277 }
278 if (msg->msg->xid != oh->xid) {
279 return OFPERR_OFPBFC_MSG_BAD_XID;
280 }
281
282 /* Reject unbundlable messages. */
283 enum ofptype type;
284 enum ofperr error = ofptype_decode(&type, msg->msg);
285 if (error) {
286 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
287 VLOG_WARN_RL(&rl, "OFPT14_BUNDLE_ADD_MESSAGE contained "
288 "message is unparsable (%s)", ofperr_get_name(error));
289 return OFPERR_OFPBFC_MSG_UNSUP; /* 'error' would be confusing. */
290 }
291
292 if (!ofputil_is_bundlable(type)) {
293 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
294 VLOG_WARN_RL(&rl, "%s message not allowed inside "
295 "OFPT14_BUNDLE_ADD_MESSAGE", ofptype_get_name(type));
296 return OFPERR_OFPBFC_MSG_UNSUP;
297 }
298 if (typep) {
299 *typep = type;
300 }
301
302 return 0;
303}
304
305struct ofpbuf *
306ofputil_encode_bundle_add(enum ofp_version ofp_version,
307 struct ofputil_bundle_add_msg *msg)
308{
309 struct ofpbuf *request;
310 struct ofp14_bundle_ctrl_msg *m;
311
312 /* Must use the same xid as the embedded message. */
313 request = ofpraw_alloc_xid(ofp_version == OFP13_VERSION
314 ? OFPRAW_ONFT13_BUNDLE_ADD_MESSAGE
315 : OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE, ofp_version,
316 msg->msg->xid, ntohs(msg->msg->length));
317 m = ofpbuf_put_zeros(request, sizeof *m);
318
319 m->bundle_id = htonl(msg->bundle_id);
320 m->flags = htons(msg->flags);
321 ofpbuf_put(request, msg->msg, ntohs(msg->msg->length));
322
323 ofpmsg_update_length(request);
324 return request;
325}
326
327/* Opens file 'file_name' and reads each line as a flow_mod or a group_mod,
328 * depending on the first keyword on each line. Stores each flow and group
329 * mods in '*bms', an array allocated on the caller's behalf, and the number of
330 * messages in '*n_bms'.
331 *
332 * Returns NULL if successful, otherwise a malloc()'d string describing the
333 * error. The caller is responsible for freeing the returned string. */
334char * OVS_WARN_UNUSED_RESULT
335parse_ofp_bundle_file(const char *file_name,
336 const struct ofputil_port_map *port_map,
337 const struct ofputil_table_map *table_map,
338 struct ofputil_bundle_msg **bms, size_t *n_bms,
339 enum ofputil_protocol *usable_protocols)
340{
341 size_t allocated_bms;
342 char *error = NULL;
343 int line_number;
344 FILE *stream;
345 struct ds ds;
346
347 *usable_protocols = OFPUTIL_P_ANY;
348
349 *bms = NULL;
350 *n_bms = 0;
351
352 stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
353 if (stream == NULL) {
354 return xasprintf("%s: open failed (%s)",
355 file_name, ovs_strerror(errno));
356 }
357
358 allocated_bms = *n_bms;
359 ds_init(&ds);
360 line_number = 0;
361 while (!ds_get_preprocessed_line(&ds, stream, &line_number)) {
362 enum ofputil_protocol usable;
363 char *s = ds_cstr(&ds);
364 size_t len;
365
366 if (*n_bms >= allocated_bms) {
367 struct ofputil_bundle_msg *new_bms;
368
369 new_bms = x2nrealloc(*bms, &allocated_bms, sizeof **bms);
370 for (size_t i = 0; i < *n_bms; i++) {
371 if (new_bms[i].type == OFPTYPE_GROUP_MOD) {
372 ovs_list_moved(&new_bms[i].gm.buckets,
373 &(*bms)[i].gm.buckets);
374 }
375 }
376 *bms = new_bms;
377 }
378
379 s += strspn(s, " \t\r\n"); /* Skip white space. */
380 len = strcspn(s, ", \t\r\n"); /* Get length of the first token. */
381
382 if (!strncmp(s, "flow", len)) {
383 s += len;
384 error = parse_ofp_flow_mod_str(&(*bms)[*n_bms].fm, s, port_map,
385 table_map, -2, &usable);
386 if (error) {
387 break;
388 }
389 (*bms)[*n_bms].type = OFPTYPE_FLOW_MOD;
390 } else if (!strncmp(s, "group", len)) {
391 s += len;
392 error = parse_ofp_group_mod_str(&(*bms)[*n_bms].gm, -2, s,
393 port_map, table_map, &usable);
394 if (error) {
395 break;
396 }
397 (*bms)[*n_bms].type = OFPTYPE_GROUP_MOD;
398 } else if (!strncmp(s, "packet-out", len)) {
399 s += len;
400 error = parse_ofp_packet_out_str(&(*bms)[*n_bms].po, s, port_map,
401 table_map, &usable);
402 if (error) {
403 break;
404 }
405 (*bms)[*n_bms].type = OFPTYPE_PACKET_OUT;
406 } else {
407 error = xasprintf("Unsupported bundle message type: %.*s",
408 (int)len, s);
409 break;
410 }
411
412 *usable_protocols &= usable; /* Each line can narrow the set. */
413 *n_bms += 1;
414 }
415
416 ds_destroy(&ds);
417 if (stream != stdin) {
418 fclose(stream);
419 }
420
421 if (error) {
422 char *err_msg = xasprintf("%s:%d: %s", file_name, line_number, error);
423 free(error);
424
425 ofputil_free_bundle_msgs(*bms, *n_bms);
426 *bms = NULL;
427 *n_bms = 0;
428 return err_msg;
429 }
430 return NULL;
431}