blob: fd477365e2a300f3e425554f5efe3690d7416bb9 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28##
29# @brief C code generation for LOXI type related maps
30#
31
Andreas Wundsam76db0062013-11-15 13:34:41 -080032import c_gen.of_g_legacy as of_g
Rich Lanea06d0c32013-03-25 08:52:03 -070033import sys
34from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080035import c_gen.type_maps as type_maps
Rich Lanea06d0c32013-03-25 08:52:03 -070036
37
38# Some number larger than small type values, but less then
39# reserved values like 0xffff
40max_type_value = 1000
41
42def gen_object_id_to_type(out):
43 out.write("""
44/**
45 * Map from object ID to primary wire type
46 *
47 * For messages, this is the header type; in particular for stats, this is
48 * the common stats request/response type. For per-stats types, use the
49 * stats type map. For things like actions, instructions or queue-props,
50 * this gives the "sub type".
51 */
52""")
53 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -070054 out.write("static const int\nof_object_to_type_map_v%d[OF_OBJECT_COUNT] = {\n"
Rich Lanea06d0c32013-03-25 08:52:03 -070055 %version)
56 out.write(" -1, /* of_object, not a valid specific type */\n")
57 for j, cls in enumerate(of_g.all_class_order):
58 comma = ""
59 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
60 comma = ","
61
62 if cls in type_maps.stats_reply_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070063 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070064 (type_maps.type_val[("of_stats_reply", version)],
65 comma, cls))
66 elif cls in type_maps.stats_request_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070067 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070068 (type_maps.type_val[("of_stats_request", version)],
69 comma, cls))
Rob Vaterlausb3f49d92013-10-01 17:57:31 -070070 elif cls in type_maps.error_msg_list:
71 out.write(" %d%s /* %s */\n" %
72 (type_maps.type_val[("of_error_msg", version)],
73 comma, cls))
Rich Lanea06d0c32013-03-25 08:52:03 -070074 elif cls in type_maps.flow_mod_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070075 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070076 (type_maps.type_val[("of_flow_mod", version)],
77 comma, cls))
Rich Lanee3113672013-12-06 17:09:57 -080078 elif cls in type_maps.group_mod_list and version > 1:
79 out.write(" %d%s /* %s */\n" %
80 (type_maps.type_val[("of_group_mod", version)],
81 comma, cls))
Rich Laneb8fc0b72013-10-24 16:55:25 -070082 elif (cls, version) in type_maps.type_val and \
83 type_maps.type_val[(cls, version)] != type_maps.invalid_type:
Andreas Wundsam53256162013-05-02 14:05:53 -070084 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070085 (type_maps.type_val[(cls, version)], comma, cls))
86 elif type_maps.message_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070087 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070088 (type_maps.type_val[("of_experimenter", version)],
89 comma, cls))
90 elif type_maps.action_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070091 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070092 (type_maps.type_val[("of_action_experimenter",
93 version)],
94 comma, cls))
95 elif type_maps.action_id_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070096 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070097 (type_maps.type_val[("of_action_id_experimenter",
98 version)],
99 comma, cls))
100 elif type_maps.instruction_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700101 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700102 (type_maps.type_val[("of_instruction_experimenter",
103 version)],
104 comma, cls))
105 elif type_maps.queue_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700106 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700107 (type_maps.type_val[("of_queue_prop_experimenter",
108 version)],
109 comma, cls))
110 elif type_maps.table_feature_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700111 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700112 (type_maps.type_val[("of_table_feature_prop_experimenter",
113 version)],
114 comma, cls))
115 else:
116 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
117 out.write("};\n\n")
118
119 out.write("""
120/**
121 * Unified map, indexed by wire version which is 1-based.
122 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700123const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700124 NULL,
125""")
126 for version in of_g.of_version_range:
127 out.write(" of_object_to_type_map_v%d,\n" % version)
128 out.write("""
129};
130""")
131
132def gen_object_id_to_extension_data(out):
133 out.write("""
134/**
135 * Extension data.
136 * @fixme There must be a better way to represent this data
137 */
138""")
139 for version in of_g.of_version_range:
140 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700141static const of_experimenter_data_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700142of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
143""" % version)
144 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
145 for j, cls in enumerate(of_g.all_class_order):
146 comma = ""
147 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
148 comma = ","
149
150 if type_maps.class_is_extension(cls, version):
151 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
152 subtype = type_maps.extension_to_subtype(cls, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700153 out.write(" {1, %s, %d}%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700154 (exp_name, subtype, comma, cls))
155 else:
156 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
157 (comma, cls))
158 out.write("};\n\n")
159
160 out.write("""
161/**
162 * Unified map, indexed by wire version which is 1-based.
163 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700164const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700165 NULL,
166""")
167 for version in of_g.of_version_range:
168 out.write(" of_object_to_extension_data_v%d,\n" % version)
169 out.write("""
170};
171""")
172
173def gen_type_to_object_id(out, type_str, prefix, template,
174 value_array, max_val):
175 """
176 Generate C maps from various message class groups to object ids
177
178 For each version, create an array mapping the type info to the
179 object ID. Then define an array containing those pointers.
180 """
181
182 # Create unified arrays and get length
183 arr_len = type_maps.type_array_len(value_array, max_val)
184 all_ars = []
185 for version, val_dict in value_array.items(): # Per version dict
186 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
187 all_ars.append(ar)
188
189 len_name = "%s_ITEM_COUNT" % prefix
190
191 for i, ar in enumerate(all_ars):
192 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -0700193 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700194 (type_str, version, len_name))
195 for i in range(arr_len):
196 comma = ""
197 if i < arr_len - 1: # Avoid ultimate comma
198 comma = ","
199
200 # Per-version length check
201 if i < len(ar):
202 v = ar[i]
203 else:
204 v = type_maps.invalid_type
205
206 if v == type_maps.invalid_type:
207 out.write(" %-30s /* %d (Invalid) */\n" %
208 ("OF_OBJECT_INVALID" + comma, i))
209 else:
210 name = (template % v.upper()) + comma
211 out.write(" %-30s /* %d */\n" % (name, i))
212 out.write("};\n")
213
214 out.write("""
215/**
216 * Maps from %(c_name)s wire type values to LOCI object ids
217 *
218 * Indexed by wire version which is 1-based.
219 */
220
Rich Laneb157b0f2013-03-27 13:55:28 -0700221const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700222 NULL,
223""" % dict(name=type_str, c_name=prefix.lower()))
224 for version in of_g.of_version_range:
225 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
226 version=version))
227 out.write("""
228};
229
Andreas Wundsam53256162013-05-02 14:05:53 -0700230""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700231 max_val=max_val, c_name=prefix.lower()))
232
233def gen_type_maps(out):
234 """
235 Generate various type maps
236 @param out The file handle to write to
237 """
238
239 out.write("#include <loci/loci.h>\n\n")
240
241 # Generate maps from wire type values to object IDs
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700242 gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
243 "OF_%s_ERROR_MSG", type_maps.error_types,
244 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700245 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
246 "OF_ACTION_%s", type_maps.action_types,
247 max_type_value)
248 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
249 "OF_ACTION_ID_%s", type_maps.action_id_types,
250 max_type_value)
251 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700252 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700253 max_type_value)
254 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
255 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
256 max_type_value)
257 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
258 "OF_TABLE_FEATURE_PROP",
259 "OF_TABLE_FEATURE_PROP_%s",
260 type_maps.table_feature_prop_types,
261 max_type_value)
262 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
263 "OF_METER_BAND_%s", type_maps.meter_band_types,
264 max_type_value)
265 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
266 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
267 max_type_value)
Rich Lanee3113672013-12-06 17:09:57 -0800268 gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
269 "OF_GROUP_%s", type_maps.group_mod_types,
270 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700271
272 # FIXME: Multipart re-organization
273 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
274 "OF_%s_STATS_REQUEST", type_maps.stats_types,
275 max_type_value)
276 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
277 "OF_%s_STATS_REPLY", type_maps.stats_types,
278 max_type_value)
279 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
280 "OF_FLOW_%s", type_maps.flow_mod_types,
281 max_type_value)
282 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
283 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
284 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
285 "OF_%s", type_maps.message_types, max_type_value)
286
287 gen_object_id_to_type(out)
288 gen_object_id_to_extension_data(out)
289 # Don't need array mapping ID to stats types right now; handled directly
290 # gen_object_id_to_stats_type(out)
291
292
293def gen_type_to_obj_map_functions(out):
294 """
295 Generate the templated static inline type map functions
296 @param out The file handle to write to
297 """
298
299 ################################################################
300 # Generate all type-to-object-ID maps in a common way
301 ################################################################
302 map_template = """
303/**
304 * %(name)s wire type to object ID array.
305 * Treat as private; use function accessor below
306 */
307
Rich Laneb157b0f2013-03-27 13:55:28 -0700308extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700309
310#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
311
312/**
313 * Map an %(name)s wire value to an OF object
314 * @param %(name)s The %(name)s type wire value
315 * @param version The version associated with the check
316 * @return The %(name)s OF object type
317 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700318 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700319 */
320static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700321of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700322{
323 if (!OF_VERSION_OKAY(version)) {
324 return OF_OBJECT_INVALID;
325 }
326 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
327 return OF_OBJECT_INVALID;
328 }
329
330 return of_%(name)s_type_to_id[version][%(name)s];
331}
332"""
333 map_with_experimenter_template = """
334/**
335 * %(name)s wire type to object ID array.
336 * Treat as private; use function accessor below
337 */
338
Rich Laneb157b0f2013-03-27 13:55:28 -0700339extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700340
341#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
342
343/**
344 * Map an %(name)s wire value to an OF object
345 * @param %(name)s The %(name)s type wire value
346 * @param version The version associated with the check
347 * @return The %(name)s OF object type
348 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700349 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700350 */
351static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700352of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700353{
354 if (!OF_VERSION_OKAY(version)) {
355 return OF_OBJECT_INVALID;
356 }
357 if (%(name)s == OF_EXPERIMENTER_TYPE) {
358 return OF_%(u_name)s_EXPERIMENTER;
359 }
360 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
361 return OF_OBJECT_INVALID;
362 }
363
364 return of_%(name)s_type_to_id[version][%(name)s];
365}
366"""
367
368 stats_template = """
369/**
370 * %(name)s wire type to object ID array.
371 * Treat as private; use function accessor below
372 */
373
Rich Laneb157b0f2013-03-27 13:55:28 -0700374extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700375
376#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
377
378/**
379 * Map an %(name)s wire value to an OF object
380 * @param %(name)s The %(name)s type wire value
381 * @param version The version associated with the check
382 * @return The %(name)s OF object type
383 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700384 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700385 */
386static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700387of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700388{
389 if (!OF_VERSION_OKAY(version)) {
390 return OF_OBJECT_INVALID;
391 }
392 if (%(name)s == OF_EXPERIMENTER_TYPE) {
393 return OF_EXPERIMENTER_%(u_name)s;
394 }
395 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
396 return OF_OBJECT_INVALID;
397 }
398
399 return of_%(name)s_type_to_id[version][%(name)s];
400}
401"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700402
403 error_msg_template = """
404/**
405 * %(name)s wire type to object ID array.
406 * Treat as private; use function accessor below
407 */
408
409extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
410
411#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
412
413/**
414 * Map an %(name)s wire value to an OF object
415 * @param %(name)s The %(name)s type wire value
416 * @param version The version associated with the check
417 * @return The %(name)s OF object type
418 * @return OF_OBJECT_INVALID if type does not map to an object
419 *
420 */
421static inline of_object_id_t
422of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
423{
424 if (!OF_VERSION_OKAY(version)) {
425 return OF_OBJECT_INVALID;
426 }
427 if (%(name)s == OF_EXPERIMENTER_TYPE) {
428 return OF_EXPERIMENTER_ERROR_MSG;
429 }
430 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
431 return OF_OBJECT_INVALID;
432 }
433
434 return of_%(name)s_type_to_id[version][%(name)s];
435}
436"""
437
Rich Lanea06d0c32013-03-25 08:52:03 -0700438 # Experimenter mapping functions
439 # Currently we support very few candidates, so we just do a
440 # list of if/elses
441 experimenter_function = """
442/**
443 * @brief Map a message known to be an exp msg to the proper object
444 *
445 * Assume that the message is a vendor/experimenter message. Determine
446 * the specific object type for the message.
447 * @param msg An OF message object (uint8_t *)
448 * @param length The number of bytes in the message (for error checking)
449 * @param version Version of message
450 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
451 *
452 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
453 */
454
455static inline of_object_id_t
456of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
457 uint32_t experimenter_id;
458 uint32_t subtype;
459
460 /* Extract experimenter and subtype value; look for match from type maps */
461 experimenter_id = of_message_experimenter_id_get(msg);
462 subtype = of_message_experimenter_subtype_get(msg);
463
464 /* Do a simple if/else search for the ver, experimenter and subtype */
465"""
466 first = True
467 for version, experimenter_lists in type_maps.extension_message_subtype.items():
468 for exp, subtypes in experimenter_lists.items():
469 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700470 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700471 (version == %(ver_name)s)) {
472""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
473 for ext_msg, subtype in subtypes.items():
474 experimenter_function += """
475 if (subtype == %(subtype)s) {
476 return %(ext_msg)s;
477 }
478""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
479 experimenter_function += """
480 }
481"""
482 experimenter_function += """
483 return OF_EXPERIMENTER;
484}
485"""
486
487 # Message need different handling
488 msg_template = """
489/**
490 * %(name)s wire type to object ID array.
491 * Treat as private; use function accessor below
492 */
493
Rich Laneb157b0f2013-03-27 13:55:28 -0700494extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700495
496#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
497
498/**
499 * Extract the type info from the message and determine its object type
500 * @param msg An OF message object (uint8_t *)
501 * @param length The number of bytes in the message (for error checking)
502 * @returns object ID or OF_OBJECT_INVALID if parse error
503 */
504
505static inline of_object_id_t
506of_message_to_object_id(of_message_t msg, int length) {
507 uint8_t type;
508 of_version_t ver;
509 of_object_id_t obj_id;
510 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700511 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700512 uint8_t flow_mod_cmd;
Rich Lane353a79f2013-11-13 10:39:56 -0800513 uint32_t experimenter, subtype;
Rich Lanee3113672013-12-06 17:09:57 -0800514 uint16_t group_mod_cmd;
Rich Lanea06d0c32013-03-25 08:52:03 -0700515
516 if (length < OF_MESSAGE_MIN_LENGTH) {
517 return OF_OBJECT_INVALID;
518 }
519 type = of_message_type_get(msg);
520 ver = of_message_version_get(msg);
521 if (!OF_VERSION_OKAY(ver)) {
522 return OF_OBJECT_INVALID;
523 }
524
525 if (type >= OF_MESSAGE_ITEM_COUNT) {
526 return OF_OBJECT_INVALID;
527 }
528
529 obj_id = of_message_type_to_id[ver][type];
530
531 /* Remap to specific message if known */
532 if (obj_id == OF_EXPERIMENTER) {
533 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
534 return OF_OBJECT_INVALID;
535 }
536 return of_message_experimenter_to_object_id(msg, ver);
537 }
538
539 /* Remap to add/delete/strict version */
540 if (obj_id == OF_FLOW_MOD) {
541 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
542 return OF_OBJECT_INVALID;
543 }
544 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
545 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
546 }
547
548 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
549 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
550 return OF_OBJECT_INVALID;
551 }
552 stats_type = of_message_stats_type_get(msg);
Rich Lane353a79f2013-11-13 10:39:56 -0800553 if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
554 if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
555 return OF_OBJECT_INVALID;
556 }
557 experimenter = of_message_stats_experimenter_id_get(msg);
558 subtype = of_message_stats_experimenter_subtype_get(msg);
559 if (obj_id == OF_STATS_REQUEST) {
560 obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
561 } else {
562 obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
563 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700564 } else {
Rich Lane353a79f2013-11-13 10:39:56 -0800565 if (obj_id == OF_STATS_REQUEST) {
566 obj_id = of_stats_request_to_object_id(stats_type, ver);
567 } else {
568 obj_id = of_stats_reply_to_object_id(stats_type, ver);
569 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 }
571 }
572
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700573 if (obj_id == OF_ERROR_MSG) {
574 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
575 return OF_OBJECT_INVALID;
576 }
577 err_type = of_message_error_type_get(msg);
578 obj_id = of_error_msg_to_object_id(err_type, ver);
579 }
580
Rich Lanee3113672013-12-06 17:09:57 -0800581 if (obj_id == OF_GROUP_MOD) {
582 if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
583 return OF_OBJECT_INVALID;
584 }
585 group_mod_cmd = of_message_group_mod_command_get(msg);
586 obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
587 }
588
Rich Lanea06d0c32013-03-25 08:52:03 -0700589 return obj_id;
590}
591"""
592
Rich Laned8d29c92013-09-24 13:46:42 -0700593 oxm_template = """
594/**
595 * oxm wire type to object ID array.
596 * Treat as private; use function accessor below
597 */
598
599extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
600
601#define OF_OXM_ITEM_COUNT %(ar_len)d\n
602
603/**
604 * Map an oxm wire value to an OF object
605 * @param oxm The oxm type wire value
606 * @param version The version associated with the check
607 * @return The oxm OF object type
608 * @return OF_OBJECT_INVALID if type does not map to an object
609 *
610 */
611static inline of_object_id_t
612of_oxm_to_object_id(uint32_t type_len, of_version_t version)
613{
614 if (!OF_VERSION_OKAY(version)) {
615 return OF_OBJECT_INVALID;
616 }
617
618 uint16_t class = (type_len >> 16) & 0xffff;
619 uint8_t masked_type = (type_len >> 8) & 0xff;
620
621 if (class == 0x8000) {
622 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
623 return OF_OBJECT_INVALID;
624 }
625
626 return of_oxm_type_to_id[version][masked_type];
627 } else if (class == 0x0003) {
628 switch (masked_type) {
629 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
630 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
Rich Lane61718362013-10-24 16:59:42 -0700631 case 0x02: return OF_OXM_BSN_LAG_ID;
632 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laneeb21c4f2013-10-28 17:34:41 -0700633 case 0x04: return OF_OXM_BSN_VRF;
634 case 0x05: return OF_OXM_BSN_VRF_MASKED;
635 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
636 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
637 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
638 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
639 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
640 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
641 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
642 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700643 default: return OF_OBJECT_INVALID;
644 }
645 } else {
646 return OF_OBJECT_INVALID;
647 }
648}
649"""
650
Rich Lanea06d0c32013-03-25 08:52:03 -0700651 # Action types array gen
652 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700653 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700654 dict(name="action", u_name="ACTION", ar_len=ar_len))
655
656 # Action ID types array gen
657 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700658 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700659 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
660
661 # Instruction types array gen
662 ar_len = type_maps.type_array_len(type_maps.instruction_types,
663 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700664 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700665 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
666
667 # Queue prop types array gen
668 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
669 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700670 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700671 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
672
673 # Table feature prop types array gen
674 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
675 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700676 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700677 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
678 ar_len=ar_len))
679
680 # Meter band types array gen
681 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
682 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700683 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700684 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
685
686 # Hello elem types array gen
687 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
688 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700689 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700690 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
691
692 # Stats types array gen
693 ar_len = type_maps.type_array_len(type_maps.stats_types,
694 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700695 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700696 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700697 out.write(stats_template %
698 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700699 ar_len=ar_len))
700
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700701 ar_len = type_maps.type_array_len(type_maps.error_types,
702 max_type_value)
703 out.write(error_msg_template %
704 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
705# out.write(error_msg_function)
706
Rich Lanea06d0c32013-03-25 08:52:03 -0700707 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700708 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700709 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
710
Rich Lanee3113672013-12-06 17:09:57 -0800711 ar_len = type_maps.type_array_len(type_maps.group_mod_types,
712 max_type_value)
713 out.write(map_template %
714 dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
715
Rich Laned8d29c92013-09-24 13:46:42 -0700716 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700717 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
718 out.write("""
719/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
720""")
Rich Laned8d29c92013-09-24 13:46:42 -0700721 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700722
Rich Laned8d29c92013-09-24 13:46:42 -0700723 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700724 out.write(experimenter_function)
725 # Must follow stats reply/request
726 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700727 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700728 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
729
730def gen_obj_to_type_map_functions(out):
731 """
732 Generate the static line maps from object IDs to types
733 @param out The file handle to write to
734 """
735
736 ################################################################
737 # Generate object ID to primary type map
738 ################################################################
739
740 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700741extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700742
743/**
744 * Map an object ID to its primary wire type value
745 * @param id An object ID
746 * @return For message objects, the type value in the OpenFlow header
747 * @return For non-message objects such as actions, instructions, OXMs
748 * returns the type value that appears in the respective sub-header
749 * @return -1 For improper version or out of bounds input
750 *
751 * NOTE that for stats request/reply, returns the header type, not the
752 * sub-type
753 *
754 * Also, note that the value is returned as a signed integer. So -1 is
755 * an error code, while 0xffff is the usual "experimenter" code.
756 */
757static inline int
758of_object_to_wire_type(of_object_id_t id, of_version_t version)
759{
760 if (!OF_VERSION_OKAY(version)) {
761 return -1;
762 }
763 if (id < 0 || id >= OF_OBJECT_COUNT) {
764 return -1;
765 }
766 return of_object_to_type_map[version][id];
767}
768
769""")
770
771 # Now for experimenter ids
772 out.write("""
773/**
774 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
775 */
776""")
777 out.write("""
778typedef struct of_experimenter_data_s {
779 int is_extension; /* Boolean indication that this is an extension */
780 uint32_t experimenter_id;
781 uint32_t subtype;
782} of_experimenter_data_t;
783
784""")
785
786 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700787extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700788
789/**
790 * Map from the object ID of an extension to the experimenter ID
791 */
792static inline uint32_t
793of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
794{
795 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
796 return (uint32_t) -1;
797 }
798 /* @fixme: Verify ver? */
799 return of_object_to_extension_data[ver][obj_id].experimenter_id;
800}
801
802/**
803 * Map from the object ID of an extension to the experimenter subtype
804 */
805static inline uint32_t
806of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
807{
808 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
809 return (uint32_t) -1;
810 }
811 /* @fixme: Verify ver? */
812 return of_object_to_extension_data[ver][obj_id].subtype;
813}
814
815/**
816 * Boolean function indicating the the given object ID/version
817 * is recognized as a supported (decode-able) extension.
818 */
819static inline int
820of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
821{
822 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
823 return (uint32_t) -1;
824 }
825 /* @fixme: Verify ver? */
826 return of_object_to_extension_data[ver][obj_id].is_extension;
827}
828""")
829
830 ################################################################
831 # Generate object ID to the stats sub-type map
832 ################################################################
833
834 out.write("""
835/**
836 * Map an object ID to a stats type
837 * @param id An object ID
838 * @return The wire value for the stats type
839 * @return -1 if not supported for this version
840 * @return -1 if id is not a specific stats type ID
841 *
842 * Note that the value is returned as a signed integer. So -1 is
843 * an error code, while 0xffff is the usual "experimenter" code.
844 */
845
846static inline int
847of_object_to_stats_type(of_object_id_t id, of_version_t version)
848{
849 if (!OF_VERSION_OKAY(version)) {
850 return -1;
851 }
852 switch (id) {
853""")
854 # Assumes 1.2 contains all stats types and type values are
855 # the same across all versions
856 stats_names = dict()
857 for ver in of_g.of_version_range:
858 for name, value in type_maps.stats_types[ver].items():
859 if name in stats_names and (not value == stats_names[name]):
860 print "ERROR stats type differ violating assumption"
861 sys.exit(1)
862 stats_names[name] = value
863
864 for name, value in stats_names.items():
865 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
866 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
867 for version in of_g.of_version_range:
868 if not name in type_maps.stats_types[version]:
869 out.write(" if (version == %s) break;\n" %
870 of_g.of_version_wire2name[version])
871 out.write(" return %d;\n" % value)
872 out.write("""
873 default:
874 break;
875 }
876 return -1; /* Not recognized as stats type object for this version */
877}
878""")
879
880 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700881 # Generate object ID to the error sub-type map
882 ################################################################
883 out.write("""
884/**
885 * Map an object ID to an error type
886 * @param id An object ID
887 * @return The wire value for the error type
888 * @return -1 if not supported for this version
889 * @return -1 if id is not a specific error type ID
890 *
891 * Note that the value is returned as a signed integer. So -1 is
892 * an error code, while 0xffff is the usual "experimenter" code.
893 */
894
895static inline int
896of_object_to_error_type(of_object_id_t id, of_version_t version)
897{
898 if (!OF_VERSION_OKAY(version)) {
899 return -1;
900 }
901 switch (id) {""")
902 error_names = set()
903 for ver in of_g.of_version_range:
904 for name in type_maps.error_types[ver]:
905 error_names.add(name)
906 for name in error_names:
907 out.write("""
908 case OF_%(name)s_ERROR_MSG:
909 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
910 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
911 break;""" % {"name": name.upper()})
912 out.write("""
913 default:
914 break;
915 }
916 return -1; /* Not recognized as error type object for this version */
917}
918""")
919
920 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700921 # Generate object ID to the flow mod sub-type map
922 ################################################################
923
924 out.write("""
925/**
926 * Map an object ID to a flow-mod command value
927 * @param id An object ID
928 * @return The wire value for the flow-mod command
929 * @return -1 if not supported for this version
930 * @return -1 if id is not a specific stats type ID
931 *
932 * Note that the value is returned as a signed integer. So -1 is
933 * an error code, while 0xffff is the usual "experimenter" code.
934 */
935
936static inline int
937of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
938{
939 if (!OF_VERSION_OKAY(version)) {
940 return -1;
941 }
942 switch (id) {
943""")
944 # Assumes 1.2 contains all stats types and type values are
945 # the same across all versions
946 flow_mod_names = dict()
947 for ver in of_g.of_version_range:
948 for name, value in type_maps.flow_mod_types[ver].items():
949 if name in flow_mod_names and \
950 (not value == flow_mod_names[name]):
951 print "ERROR flow mod command differ violating assumption"
952 sys.exit(1)
953 flow_mod_names[name] = value
954
955 for name, value in flow_mod_names.items():
956 out.write(" case OF_FLOW_%s:\n" % name.upper())
957 for version in of_g.of_version_range:
958 if not name in type_maps.flow_mod_types[version]:
959 out.write(" if (version == %s) break;\n" %
960 of_g.of_version_wire2name[version])
961 out.write(" return %d;\n" % value)
962 out.write("""
963 default:
964 break;
965 }
966 return -1; /* Not recognized as flow mod type object for this version */
967}
968
969""")
970
Rich Lanee3113672013-12-06 17:09:57 -0800971 ################################################################
972 # Generate object ID to the group mod sub-type map
973 ################################################################
974
975 out.write("""
976/**
977 * Map an object ID to a group-mod command value
978 * @param id An object ID
979 * @return The wire value for the group-mod command
980 * @return -1 if not supported for this version
981 * @return -1 if id is not a specific stats type ID
982 *
983 * Note that the value is returned as a signed integer. So -1 is
984 * an error code, while 0xffff is the usual "experimenter" code.
985 */
986
987static inline int
988of_object_to_group_mod_command(of_object_id_t id, of_version_t version)
989{
990 if (!OF_VERSION_OKAY(version)) {
991 return -1;
992 }
993 switch (id) {""")
994 group_mod_names = set()
995 for ver in of_g.of_version_range:
996 for name in type_maps.group_mod_types[ver]:
997 group_mod_names.add(name)
998 for name in group_mod_names:
999 out.write("""
1000 case OF_GROUP_%(name)s:
1001 if (OF_GROUP_MOD_COMMAND_%(name)s_SUPPORTED(version))
1002 return OF_GROUP_MOD_COMMAND_%(name)s_BY_VERSION(version);
1003 break;""" % {"name": name.upper()})
1004 out.write("""
1005 default:
1006 break;
1007 }
1008 return -1; /* Not recognized as group mod type object for this version */
1009}
1010
1011""")
1012
Rich Lanea06d0c32013-03-25 08:52:03 -07001013def gen_type_maps_header(out):
1014 """
1015 Generate various header file declarations for type maps
1016 @param out The file handle to write to
1017 """
1018
1019 out.write("""
1020/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001021 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -07001022 * top level message: Action, instruction, error, stats, queue_props, oxm
1023 */
1024#define OF_EXPERIMENTER_TYPE 0xffff
Rich Lane353a79f2013-11-13 10:39:56 -08001025
1026int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
1027int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
Rich Lanea06d0c32013-03-25 08:52:03 -07001028""")
1029 gen_type_to_obj_map_functions(out)
1030 gen_obj_to_type_map_functions(out)
1031
Rich Laneb157b0f2013-03-27 13:55:28 -07001032 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -07001033 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001034
1035 out.write("""
1036/**
1037 * Map a message in a wire buffer object to its OF object id.
1038 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1039 * @returns The object ID of the message
1040 * @returns OF_OBJECT_INVALID if unable to parse the message type
1041 */
1042
1043static inline of_object_id_t
1044of_wire_object_id_get(of_wire_buffer_t *wbuf)
1045{
1046 of_message_t msg;
1047
1048 msg = (of_message_t)WBUF_BUF(wbuf);
1049 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
1050}
1051
1052/**
1053 * Use the type/length from the wire buffer and init the object
1054 * @param obj The object being initialized
1055 * @param base_object_id If > 0, this indicates the base object
1056 * @param max_len If > 0, the max length to expect for the obj
1057 * type for inheritance checking
1058 * @return OF_ERROR_
1059 *
1060 * Used for inheritance type objects such as actions and OXMs
1061 * The type is checked and if valid, the object is initialized.
1062 * Then the length is taken from the buffer.
1063 *
1064 * Note that the object version must already be properly set.
1065 */
1066static inline int
1067of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
1068 int max_len)
1069{
1070 if (obj->wire_type_get != NULL) {
1071 of_object_id_t id;
1072 obj->wire_type_get(obj, &id);
1073 if (!of_wire_id_valid(id, base_object_id)) {
1074 return OF_ERROR_PARSE;
1075 }
1076 obj->object_id = id;
1077 /* Call the init function for this object type; do not push to wire */
1078 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
1079 }
1080 if (obj->wire_length_get != NULL) {
1081 int length;
1082 obj->wire_length_get(obj, &length);
1083 if (length < 0 || (max_len > 0 && length > max_len)) {
1084 return OF_ERROR_PARSE;
1085 }
1086 obj->length = length;
1087 } else {
1088 /* @fixme Does this cover everything else? */
1089 obj->length = of_object_fixed_len[obj->version][base_object_id];
1090 }
1091
1092 return OF_ERROR_NONE;
1093}
1094
1095""")
1096
1097 # Generate the function that sets the object type fields
1098 out.write("""
1099
1100/**
1101 * Map a message in a wire buffer object to its OF object id.
1102 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1103 * @returns The object ID of the message
1104 * @returns OF_OBJECT_INVALID if unable to parse the message type
1105 *
1106 * Version must be set in the buffer prior to calling this routine
1107 */
1108
1109static inline int
1110of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
1111{
1112 int type;
1113 of_version_t ver;
1114 of_message_t msg;
1115
1116 msg = (of_message_t)WBUF_BUF(wbuf);
1117
1118 ver = of_message_version_get(msg);
1119
1120 /* ASSERT(id is a message object) */
1121
1122 if ((type = of_object_to_wire_type(id, ver)) < 0) {
1123 return OF_ERROR_PARAM;
1124 }
1125 of_message_type_set(msg, type);
1126
1127 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
1128 /* It's a stats obj */
1129 of_message_stats_type_set(msg, type);
Rich Lane353a79f2013-11-13 10:39:56 -08001130 if (type == OF_STATS_TYPE_EXPERIMENTER) {
1131 switch (id) {
1132 case OF_BSN_LACP_STATS_REQUEST:
1133 case OF_BSN_LACP_STATS_REPLY:
1134 of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
1135 of_message_stats_experimenter_subtype_set(msg, 1);
1136 break;
Wilson Ng45386fb2013-12-03 13:46:42 -08001137 case OF_BSN_SWITCH_PIPELINE_STATS_REQUEST:
1138 case OF_BSN_SWITCH_PIPELINE_STATS_REPLY:
1139 of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
1140 of_message_stats_experimenter_subtype_set(msg, 6);
1141 break;
Rich Lane353a79f2013-11-13 10:39:56 -08001142 default:
1143 break;
1144 }
1145 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001146 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001147 if ((type = of_object_to_error_type(id, ver)) >= 0) {
Rob Vaterlausb5e8c832013-10-04 12:50:23 -07001148 /* It's an error obj */
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001149 of_message_error_type_set(msg, type);
1150 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001151 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
1152 /* It's a flow mod obj */
1153 of_message_flow_mod_command_set(msg, ver, type);
1154 }
Rich Lanee3113672013-12-06 17:09:57 -08001155 if ((type = of_object_to_group_mod_command(id, ver)) >= 0) {
1156 /* It's a group mod obj */
1157 of_message_group_mod_command_set(msg, type);
1158 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001159 if (of_object_id_is_extension(id, ver)) {
1160 uint32_t val32;
1161
1162 /* Set the experimenter and subtype codes */
1163 val32 = of_extension_to_experimenter_id(id, ver);
1164 of_message_experimenter_id_set(msg, val32);
1165 val32 = of_extension_to_experimenter_subtype(id, ver);
1166 of_message_experimenter_subtype_set(msg, val32);
1167 }
1168
1169 return OF_ERROR_NONE;
1170}
1171""")
1172
1173def gen_type_data_header(out):
1174
1175 out.write("""
1176/****************************************************************
1177 *
1178 * The following declarations are for type and length calculations.
1179 * Implementations may be found in of_type_maps.c
1180 *
1181 ****************************************************************/
1182/*
1183 * Special case length functions for objects with
1184 */
1185""")
1186 for ((cls, name), prev) in of_g.special_offsets.items():
1187 s_cls = cls[3:] # take off of_
1188 out.write("""
1189/**
1190 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001191 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 * length of %(name)s
1193 * @param bytes[out] Where to store the calculated length
1194 *
1195 * Preceding data member is %(prev)s.
1196 */
1197extern int of_length_%(s_cls)s_%(name)s_get(
1198 %(cls)s_t *obj, int *bytes);
1199
1200/**
1201 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001202 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001203 * length of %(name)s
1204 * @param offset[out] Where to store the calculated length
1205 *
1206 * Preceding data member is %(prev)s.
1207 */
1208extern int of_offset_%(s_cls)s_%(name)s_get(
1209 %(cls)s_t *obj, int *offset);
1210""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1211
1212# NOT NEEDED YET
1213# # For non-message, variable length objects, give a fun that
1214# # calculates the length
1215# for cls in of_g.standard_class_order:
1216# s_cls = cls[3:] # take off of_
1217# if !type_is_var_len(cls, version):
1218# continue
1219# out.write("""
1220# /**
1221# * Special length calculation for variable length object %(cls)s
1222# * @param obj An object of type %(cls)s whose length is being calculated
1223# * @param bytes[out] Where to store the calculated length
1224# *
1225# * The assumption is that the length member of the object is not
1226# * valid and the length needs to be calculated from other information
1227# * such as the parent.
1228# */
1229# extern int of_length_%(s_cls)s_get(
1230# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001231# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001232
1233 out.write("""
1234/****************************************************************
1235 * Wire type/length functions.
1236 ****************************************************************/
1237
1238extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1239extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1240
1241extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1242extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1243extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1244extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1245
1246extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1247extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1248
1249extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1250
1251/* Wire length is uint16 at front of structure */
1252extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1253extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1254
1255extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1256extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001257extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001258 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001259extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001260 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001261extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001262 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001263extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001264 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001265extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001266 of_object_id_t *id);
1267
Rich Lane47085722013-07-12 16:27:04 -07001268#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001269#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001270 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001271
1272extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1273extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1274
1275extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1276 int *bytes);
1277extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1278extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1279extern int of_extension_object_wire_push(of_object_t *obj);
1280
1281""")
1282
1283
1284def gen_length_array(out):
1285 """
1286 Generate an array giving the lengths of all objects/versions
1287 @param out The file handle to which to write
1288 """
1289 out.write("""
1290/**
1291 * An array with the number of bytes in the fixed length part
1292 * of each OF object
1293 */
1294""")
1295
1296 for version in of_g.of_version_range:
1297 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001298static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001299 -1, /* of_object is not instantiable */
1300""" % version)
1301 for i, cls in enumerate(of_g.all_class_order):
1302 comma = ","
1303 if i == len(of_g.all_class_order) - 1:
1304 comma = ""
1305 val = "-1" + comma
1306 if (cls, version) in of_g.base_length:
1307 val = str(of_g.base_length[(cls, version)]) + comma
1308 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1309 out.write("};\n")
1310
1311 out.write("""
1312/**
1313 * Unified map of fixed length part of each object
1314 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001315const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001316 NULL,
1317""")
1318 for version in of_g.of_version_range:
1319 out.write(" of_object_fixed_len_v%d,\n" % version)
1320 out.write("""
1321};
1322""")
1323
Andreas Wundsam53256162013-05-02 14:05:53 -07001324
Rich Lanef70be942013-07-18 13:33:14 -07001325def gen_extra_length_array(out):
1326 """
1327 Generate an array giving the extra lengths of all objects/versions
1328 @param out The file handle to which to write
1329 """
1330 out.write("""
1331/**
1332 * An array with the number of bytes in the extra length part
1333 * of each OF object
1334 */
1335""")
1336
1337 for version in of_g.of_version_range:
1338 out.write("""
1339static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1340 -1, /* of_object is not instantiable */
1341""" % version)
1342 for i, cls in enumerate(of_g.all_class_order):
1343 comma = ","
1344 if i == len(of_g.all_class_order) - 1:
1345 comma = ""
1346 val = "-1" + comma
1347 if (cls, version) in of_g.base_length:
1348 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1349 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1350 out.write("};\n")
1351
1352 out.write("""
1353/**
1354 * Unified map of extra length part of each object
1355 */
1356const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1357 NULL,
1358""")
1359 for version in of_g.of_version_range:
1360 out.write(" of_object_extra_len_v%d,\n" % version)
1361 out.write("""
1362};
1363""")
1364
1365
Rich Lanea06d0c32013-03-25 08:52:03 -07001366################################################################
1367################################################################
1368
1369# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1370def gen_object_id_to_stats_type(out):
1371 out.write("""
1372/**
1373 * Map from message object ID to stats type
1374 *
1375 * All message object IDs are mapped for simplicity
1376 */
1377""")
1378 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001379 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001380 out.write(" -1, /* of_object (invalid) */\n");
1381 for cls in of_g.ordered_messages:
1382 name = cls[3:]
1383 name = name[:name.find("_stats")]
1384 if (((cls in type_maps.stats_reply_list) or
1385 (cls in type_maps.stats_request_list)) and
1386 name in type_maps.stats_types[i]):
1387 out.write(" %d, /* %s */\n" %
1388 (type_maps.stats_types[i][name], cls))
1389 else:
1390 out.write(" -1, /* %s (invalid) */\n" % cls)
1391 out.write("};\n\n")
1392
1393 out.write("""
1394/**
1395 * Unified map, indexed by wire version which is 1-based.
1396 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001397const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001398 NULL,
1399""")
1400 for version in of_g.of_version_range:
1401 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1402 out.write("""
1403};
1404""")
1405