blob: 9644fdb73e12fde3e560d332b5c1593763d5413a [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
32import of_g
33import sys
34from generic_utils import *
Rich Lanea06d0c32013-03-25 08:52:03 -070035import loxi_front_end.type_maps as type_maps
36
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))
78 elif (cls, version) in type_maps.type_val:
Andreas Wundsam53256162013-05-02 14:05:53 -070079 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070080 (type_maps.type_val[(cls, version)], comma, cls))
81 elif type_maps.message_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070082 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070083 (type_maps.type_val[("of_experimenter", version)],
84 comma, cls))
85 elif type_maps.action_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070086 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070087 (type_maps.type_val[("of_action_experimenter",
88 version)],
89 comma, cls))
90 elif type_maps.action_id_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_id_experimenter",
93 version)],
94 comma, cls))
95 elif type_maps.instruction_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_instruction_experimenter",
98 version)],
99 comma, cls))
100 elif type_maps.queue_prop_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_queue_prop_experimenter",
103 version)],
104 comma, cls))
105 elif type_maps.table_feature_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_table_feature_prop_experimenter",
108 version)],
109 comma, cls))
110 else:
111 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
112 out.write("};\n\n")
113
114 out.write("""
115/**
116 * Unified map, indexed by wire version which is 1-based.
117 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700118const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700119 NULL,
120""")
121 for version in of_g.of_version_range:
122 out.write(" of_object_to_type_map_v%d,\n" % version)
123 out.write("""
124};
125""")
126
127def gen_object_id_to_extension_data(out):
128 out.write("""
129/**
130 * Extension data.
131 * @fixme There must be a better way to represent this data
132 */
133""")
134 for version in of_g.of_version_range:
135 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700136static const of_experimenter_data_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700137of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
138""" % version)
139 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
140 for j, cls in enumerate(of_g.all_class_order):
141 comma = ""
142 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
143 comma = ","
144
145 if type_maps.class_is_extension(cls, version):
146 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
147 subtype = type_maps.extension_to_subtype(cls, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700148 out.write(" {1, %s, %d}%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 (exp_name, subtype, comma, cls))
150 else:
151 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
152 (comma, cls))
153 out.write("};\n\n")
154
155 out.write("""
156/**
157 * Unified map, indexed by wire version which is 1-based.
158 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700159const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700160 NULL,
161""")
162 for version in of_g.of_version_range:
163 out.write(" of_object_to_extension_data_v%d,\n" % version)
164 out.write("""
165};
166""")
167
168def gen_type_to_object_id(out, type_str, prefix, template,
169 value_array, max_val):
170 """
171 Generate C maps from various message class groups to object ids
172
173 For each version, create an array mapping the type info to the
174 object ID. Then define an array containing those pointers.
175 """
176
177 # Create unified arrays and get length
178 arr_len = type_maps.type_array_len(value_array, max_val)
179 all_ars = []
180 for version, val_dict in value_array.items(): # Per version dict
181 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
182 all_ars.append(ar)
183
184 len_name = "%s_ITEM_COUNT" % prefix
185
186 for i, ar in enumerate(all_ars):
187 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -0700188 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700189 (type_str, version, len_name))
190 for i in range(arr_len):
191 comma = ""
192 if i < arr_len - 1: # Avoid ultimate comma
193 comma = ","
194
195 # Per-version length check
196 if i < len(ar):
197 v = ar[i]
198 else:
199 v = type_maps.invalid_type
200
201 if v == type_maps.invalid_type:
202 out.write(" %-30s /* %d (Invalid) */\n" %
203 ("OF_OBJECT_INVALID" + comma, i))
204 else:
205 name = (template % v.upper()) + comma
206 out.write(" %-30s /* %d */\n" % (name, i))
207 out.write("};\n")
208
209 out.write("""
210/**
211 * Maps from %(c_name)s wire type values to LOCI object ids
212 *
213 * Indexed by wire version which is 1-based.
214 */
215
Rich Laneb157b0f2013-03-27 13:55:28 -0700216const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700217 NULL,
218""" % dict(name=type_str, c_name=prefix.lower()))
219 for version in of_g.of_version_range:
220 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
221 version=version))
222 out.write("""
223};
224
Andreas Wundsam53256162013-05-02 14:05:53 -0700225""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700226 max_val=max_val, c_name=prefix.lower()))
227
228def gen_type_maps(out):
229 """
230 Generate various type maps
231 @param out The file handle to write to
232 """
233
234 out.write("#include <loci/loci.h>\n\n")
235
236 # Generate maps from wire type values to object IDs
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700237 gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
238 "OF_%s_ERROR_MSG", type_maps.error_types,
239 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700240 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
241 "OF_ACTION_%s", type_maps.action_types,
242 max_type_value)
243 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
244 "OF_ACTION_ID_%s", type_maps.action_id_types,
245 max_type_value)
246 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700247 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700248 max_type_value)
249 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
250 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
251 max_type_value)
252 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
253 "OF_TABLE_FEATURE_PROP",
254 "OF_TABLE_FEATURE_PROP_%s",
255 type_maps.table_feature_prop_types,
256 max_type_value)
257 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
258 "OF_METER_BAND_%s", type_maps.meter_band_types,
259 max_type_value)
260 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
261 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
262 max_type_value)
263
264 # FIXME: Multipart re-organization
265 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
266 "OF_%s_STATS_REQUEST", type_maps.stats_types,
267 max_type_value)
268 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
269 "OF_%s_STATS_REPLY", type_maps.stats_types,
270 max_type_value)
271 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
272 "OF_FLOW_%s", type_maps.flow_mod_types,
273 max_type_value)
274 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
275 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
276 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
277 "OF_%s", type_maps.message_types, max_type_value)
278
279 gen_object_id_to_type(out)
280 gen_object_id_to_extension_data(out)
281 # Don't need array mapping ID to stats types right now; handled directly
282 # gen_object_id_to_stats_type(out)
283
284
285def gen_type_to_obj_map_functions(out):
286 """
287 Generate the templated static inline type map functions
288 @param out The file handle to write to
289 """
290
291 ################################################################
292 # Generate all type-to-object-ID maps in a common way
293 ################################################################
294 map_template = """
295/**
296 * %(name)s wire type to object ID array.
297 * Treat as private; use function accessor below
298 */
299
Rich Laneb157b0f2013-03-27 13:55:28 -0700300extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700301
302#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
303
304/**
305 * Map an %(name)s wire value to an OF object
306 * @param %(name)s The %(name)s type wire value
307 * @param version The version associated with the check
308 * @return The %(name)s OF object type
309 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700310 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700311 */
312static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700313of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700314{
315 if (!OF_VERSION_OKAY(version)) {
316 return OF_OBJECT_INVALID;
317 }
318 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
319 return OF_OBJECT_INVALID;
320 }
321
322 return of_%(name)s_type_to_id[version][%(name)s];
323}
324"""
325 map_with_experimenter_template = """
326/**
327 * %(name)s wire type to object ID array.
328 * Treat as private; use function accessor below
329 */
330
Rich Laneb157b0f2013-03-27 13:55:28 -0700331extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700332
333#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
334
335/**
336 * Map an %(name)s wire value to an OF object
337 * @param %(name)s The %(name)s type wire value
338 * @param version The version associated with the check
339 * @return The %(name)s OF object type
340 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700341 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700342 */
343static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700344of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700345{
346 if (!OF_VERSION_OKAY(version)) {
347 return OF_OBJECT_INVALID;
348 }
349 if (%(name)s == OF_EXPERIMENTER_TYPE) {
350 return OF_%(u_name)s_EXPERIMENTER;
351 }
352 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
353 return OF_OBJECT_INVALID;
354 }
355
356 return of_%(name)s_type_to_id[version][%(name)s];
357}
358"""
359
360 stats_template = """
361/**
362 * %(name)s wire type to object ID array.
363 * Treat as private; use function accessor below
364 */
365
Rich Laneb157b0f2013-03-27 13:55:28 -0700366extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700367
368#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
369
370/**
371 * Map an %(name)s wire value to an OF object
372 * @param %(name)s The %(name)s type wire value
373 * @param version The version associated with the check
374 * @return The %(name)s OF object type
375 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700376 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700377 */
378static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700379of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700380{
381 if (!OF_VERSION_OKAY(version)) {
382 return OF_OBJECT_INVALID;
383 }
384 if (%(name)s == OF_EXPERIMENTER_TYPE) {
385 return OF_EXPERIMENTER_%(u_name)s;
386 }
387 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
388 return OF_OBJECT_INVALID;
389 }
390
391 return of_%(name)s_type_to_id[version][%(name)s];
392}
393"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700394
395 error_msg_template = """
396/**
397 * %(name)s wire type to object ID array.
398 * Treat as private; use function accessor below
399 */
400
401extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
402
403#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
404
405/**
406 * Map an %(name)s wire value to an OF object
407 * @param %(name)s The %(name)s type wire value
408 * @param version The version associated with the check
409 * @return The %(name)s OF object type
410 * @return OF_OBJECT_INVALID if type does not map to an object
411 *
412 */
413static inline of_object_id_t
414of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
415{
416 if (!OF_VERSION_OKAY(version)) {
417 return OF_OBJECT_INVALID;
418 }
419 if (%(name)s == OF_EXPERIMENTER_TYPE) {
420 return OF_EXPERIMENTER_ERROR_MSG;
421 }
422 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
423 return OF_OBJECT_INVALID;
424 }
425
426 return of_%(name)s_type_to_id[version][%(name)s];
427}
428"""
429
Rich Lanea06d0c32013-03-25 08:52:03 -0700430 # Experimenter mapping functions
431 # Currently we support very few candidates, so we just do a
432 # list of if/elses
433 experimenter_function = """
434/**
435 * @brief Map a message known to be an exp msg to the proper object
436 *
437 * Assume that the message is a vendor/experimenter message. Determine
438 * the specific object type for the message.
439 * @param msg An OF message object (uint8_t *)
440 * @param length The number of bytes in the message (for error checking)
441 * @param version Version of message
442 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
443 *
444 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
445 */
446
447static inline of_object_id_t
448of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
449 uint32_t experimenter_id;
450 uint32_t subtype;
451
452 /* Extract experimenter and subtype value; look for match from type maps */
453 experimenter_id = of_message_experimenter_id_get(msg);
454 subtype = of_message_experimenter_subtype_get(msg);
455
456 /* Do a simple if/else search for the ver, experimenter and subtype */
457"""
458 first = True
459 for version, experimenter_lists in type_maps.extension_message_subtype.items():
460 for exp, subtypes in experimenter_lists.items():
461 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700462 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700463 (version == %(ver_name)s)) {
464""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
465 for ext_msg, subtype in subtypes.items():
466 experimenter_function += """
467 if (subtype == %(subtype)s) {
468 return %(ext_msg)s;
469 }
470""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
471 experimenter_function += """
472 }
473"""
474 experimenter_function += """
475 return OF_EXPERIMENTER;
476}
477"""
478
479 # Message need different handling
480 msg_template = """
481/**
482 * %(name)s wire type to object ID array.
483 * Treat as private; use function accessor below
484 */
485
Rich Laneb157b0f2013-03-27 13:55:28 -0700486extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700487
488#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
489
490/**
491 * Extract the type info from the message and determine its object type
492 * @param msg An OF message object (uint8_t *)
493 * @param length The number of bytes in the message (for error checking)
494 * @returns object ID or OF_OBJECT_INVALID if parse error
495 */
496
497static inline of_object_id_t
498of_message_to_object_id(of_message_t msg, int length) {
499 uint8_t type;
500 of_version_t ver;
501 of_object_id_t obj_id;
502 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700503 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700504 uint8_t flow_mod_cmd;
505
506 if (length < OF_MESSAGE_MIN_LENGTH) {
507 return OF_OBJECT_INVALID;
508 }
509 type = of_message_type_get(msg);
510 ver = of_message_version_get(msg);
511 if (!OF_VERSION_OKAY(ver)) {
512 return OF_OBJECT_INVALID;
513 }
514
515 if (type >= OF_MESSAGE_ITEM_COUNT) {
516 return OF_OBJECT_INVALID;
517 }
518
519 obj_id = of_message_type_to_id[ver][type];
520
521 /* Remap to specific message if known */
522 if (obj_id == OF_EXPERIMENTER) {
523 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
524 return OF_OBJECT_INVALID;
525 }
526 return of_message_experimenter_to_object_id(msg, ver);
527 }
528
529 /* Remap to add/delete/strict version */
530 if (obj_id == OF_FLOW_MOD) {
531 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
532 return OF_OBJECT_INVALID;
533 }
534 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
535 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
536 }
537
538 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
539 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
540 return OF_OBJECT_INVALID;
541 }
542 stats_type = of_message_stats_type_get(msg);
543 if (obj_id == OF_STATS_REQUEST) {
544 obj_id = of_stats_request_to_object_id(stats_type, ver);
545 } else {
546 obj_id = of_stats_reply_to_object_id(stats_type, ver);
547 }
548 }
549
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700550 if (obj_id == OF_ERROR_MSG) {
551 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
552 return OF_OBJECT_INVALID;
553 }
554 err_type = of_message_error_type_get(msg);
555 obj_id = of_error_msg_to_object_id(err_type, ver);
556 }
557
Rich Lanea06d0c32013-03-25 08:52:03 -0700558 return obj_id;
559}
560"""
561
Rich Laned8d29c92013-09-24 13:46:42 -0700562 oxm_template = """
563/**
564 * oxm wire type to object ID array.
565 * Treat as private; use function accessor below
566 */
567
568extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
569
570#define OF_OXM_ITEM_COUNT %(ar_len)d\n
571
572/**
573 * Map an oxm wire value to an OF object
574 * @param oxm The oxm type wire value
575 * @param version The version associated with the check
576 * @return The oxm OF object type
577 * @return OF_OBJECT_INVALID if type does not map to an object
578 *
579 */
580static inline of_object_id_t
581of_oxm_to_object_id(uint32_t type_len, of_version_t version)
582{
583 if (!OF_VERSION_OKAY(version)) {
584 return OF_OBJECT_INVALID;
585 }
586
587 uint16_t class = (type_len >> 16) & 0xffff;
588 uint8_t masked_type = (type_len >> 8) & 0xff;
589
590 if (class == 0x8000) {
591 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
592 return OF_OBJECT_INVALID;
593 }
594
595 return of_oxm_type_to_id[version][masked_type];
596 } else if (class == 0x0003) {
597 switch (masked_type) {
598 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
599 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
600 default: return OF_OBJECT_INVALID;
601 }
602 } else {
603 return OF_OBJECT_INVALID;
604 }
605}
606"""
607
Rich Lanea06d0c32013-03-25 08:52:03 -0700608 # Action types array gen
609 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700610 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700611 dict(name="action", u_name="ACTION", ar_len=ar_len))
612
613 # Action ID types array gen
614 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700615 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700616 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
617
618 # Instruction types array gen
619 ar_len = type_maps.type_array_len(type_maps.instruction_types,
620 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700621 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700622 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
623
624 # Queue prop types array gen
625 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
626 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700627 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700628 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
629
630 # Table feature prop types array gen
631 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
632 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700633 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700634 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
635 ar_len=ar_len))
636
637 # Meter band types array gen
638 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
639 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700640 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700641 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
642
643 # Hello elem types array gen
644 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
645 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700646 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700647 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
648
649 # Stats types array gen
650 ar_len = type_maps.type_array_len(type_maps.stats_types,
651 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700652 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700653 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700654 out.write(stats_template %
655 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700656 ar_len=ar_len))
657
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700658 ar_len = type_maps.type_array_len(type_maps.error_types,
659 max_type_value)
660 out.write(error_msg_template %
661 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
662# out.write(error_msg_function)
663
Rich Lanea06d0c32013-03-25 08:52:03 -0700664 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700665 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700666 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
667
Rich Laned8d29c92013-09-24 13:46:42 -0700668 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700669 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
670 out.write("""
671/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
672""")
Rich Laned8d29c92013-09-24 13:46:42 -0700673 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700674
Rich Laned8d29c92013-09-24 13:46:42 -0700675 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700676 out.write(experimenter_function)
677 # Must follow stats reply/request
678 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700679 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700680 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
681
682def gen_obj_to_type_map_functions(out):
683 """
684 Generate the static line maps from object IDs to types
685 @param out The file handle to write to
686 """
687
688 ################################################################
689 # Generate object ID to primary type map
690 ################################################################
691
692 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700693extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700694
695/**
696 * Map an object ID to its primary wire type value
697 * @param id An object ID
698 * @return For message objects, the type value in the OpenFlow header
699 * @return For non-message objects such as actions, instructions, OXMs
700 * returns the type value that appears in the respective sub-header
701 * @return -1 For improper version or out of bounds input
702 *
703 * NOTE that for stats request/reply, returns the header type, not the
704 * sub-type
705 *
706 * Also, note that the value is returned as a signed integer. So -1 is
707 * an error code, while 0xffff is the usual "experimenter" code.
708 */
709static inline int
710of_object_to_wire_type(of_object_id_t id, of_version_t version)
711{
712 if (!OF_VERSION_OKAY(version)) {
713 return -1;
714 }
715 if (id < 0 || id >= OF_OBJECT_COUNT) {
716 return -1;
717 }
718 return of_object_to_type_map[version][id];
719}
720
721""")
722
723 # Now for experimenter ids
724 out.write("""
725/**
726 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
727 */
728""")
729 out.write("""
730typedef struct of_experimenter_data_s {
731 int is_extension; /* Boolean indication that this is an extension */
732 uint32_t experimenter_id;
733 uint32_t subtype;
734} of_experimenter_data_t;
735
736""")
737
738 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700739extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700740
741/**
742 * Map from the object ID of an extension to the experimenter ID
743 */
744static inline uint32_t
745of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
746{
747 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
748 return (uint32_t) -1;
749 }
750 /* @fixme: Verify ver? */
751 return of_object_to_extension_data[ver][obj_id].experimenter_id;
752}
753
754/**
755 * Map from the object ID of an extension to the experimenter subtype
756 */
757static inline uint32_t
758of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
759{
760 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
761 return (uint32_t) -1;
762 }
763 /* @fixme: Verify ver? */
764 return of_object_to_extension_data[ver][obj_id].subtype;
765}
766
767/**
768 * Boolean function indicating the the given object ID/version
769 * is recognized as a supported (decode-able) extension.
770 */
771static inline int
772of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
773{
774 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
775 return (uint32_t) -1;
776 }
777 /* @fixme: Verify ver? */
778 return of_object_to_extension_data[ver][obj_id].is_extension;
779}
780""")
781
782 ################################################################
783 # Generate object ID to the stats sub-type map
784 ################################################################
785
786 out.write("""
787/**
788 * Map an object ID to a stats type
789 * @param id An object ID
790 * @return The wire value for the stats type
791 * @return -1 if not supported for this version
792 * @return -1 if id is not a specific stats type ID
793 *
794 * Note that the value is returned as a signed integer. So -1 is
795 * an error code, while 0xffff is the usual "experimenter" code.
796 */
797
798static inline int
799of_object_to_stats_type(of_object_id_t id, of_version_t version)
800{
801 if (!OF_VERSION_OKAY(version)) {
802 return -1;
803 }
804 switch (id) {
805""")
806 # Assumes 1.2 contains all stats types and type values are
807 # the same across all versions
808 stats_names = dict()
809 for ver in of_g.of_version_range:
810 for name, value in type_maps.stats_types[ver].items():
811 if name in stats_names and (not value == stats_names[name]):
812 print "ERROR stats type differ violating assumption"
813 sys.exit(1)
814 stats_names[name] = value
815
816 for name, value in stats_names.items():
817 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
818 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
819 for version in of_g.of_version_range:
820 if not name in type_maps.stats_types[version]:
821 out.write(" if (version == %s) break;\n" %
822 of_g.of_version_wire2name[version])
823 out.write(" return %d;\n" % value)
824 out.write("""
825 default:
826 break;
827 }
828 return -1; /* Not recognized as stats type object for this version */
829}
830""")
831
832 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700833 # Generate object ID to the error sub-type map
834 ################################################################
835 out.write("""
836/**
837 * Map an object ID to an error type
838 * @param id An object ID
839 * @return The wire value for the error type
840 * @return -1 if not supported for this version
841 * @return -1 if id is not a specific error type ID
842 *
843 * Note that the value is returned as a signed integer. So -1 is
844 * an error code, while 0xffff is the usual "experimenter" code.
845 */
846
847static inline int
848of_object_to_error_type(of_object_id_t id, of_version_t version)
849{
850 if (!OF_VERSION_OKAY(version)) {
851 return -1;
852 }
853 switch (id) {""")
854 error_names = set()
855 for ver in of_g.of_version_range:
856 for name in type_maps.error_types[ver]:
857 error_names.add(name)
858 for name in error_names:
859 out.write("""
860 case OF_%(name)s_ERROR_MSG:
861 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
862 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
863 break;""" % {"name": name.upper()})
864 out.write("""
865 default:
866 break;
867 }
868 return -1; /* Not recognized as error type object for this version */
869}
870""")
871
872 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700873 # Generate object ID to the flow mod sub-type map
874 ################################################################
875
876 out.write("""
877/**
878 * Map an object ID to a flow-mod command value
879 * @param id An object ID
880 * @return The wire value for the flow-mod command
881 * @return -1 if not supported for this version
882 * @return -1 if id is not a specific stats type ID
883 *
884 * Note that the value is returned as a signed integer. So -1 is
885 * an error code, while 0xffff is the usual "experimenter" code.
886 */
887
888static inline int
889of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
890{
891 if (!OF_VERSION_OKAY(version)) {
892 return -1;
893 }
894 switch (id) {
895""")
896 # Assumes 1.2 contains all stats types and type values are
897 # the same across all versions
898 flow_mod_names = dict()
899 for ver in of_g.of_version_range:
900 for name, value in type_maps.flow_mod_types[ver].items():
901 if name in flow_mod_names and \
902 (not value == flow_mod_names[name]):
903 print "ERROR flow mod command differ violating assumption"
904 sys.exit(1)
905 flow_mod_names[name] = value
906
907 for name, value in flow_mod_names.items():
908 out.write(" case OF_FLOW_%s:\n" % name.upper())
909 for version in of_g.of_version_range:
910 if not name in type_maps.flow_mod_types[version]:
911 out.write(" if (version == %s) break;\n" %
912 of_g.of_version_wire2name[version])
913 out.write(" return %d;\n" % value)
914 out.write("""
915 default:
916 break;
917 }
918 return -1; /* Not recognized as flow mod type object for this version */
919}
920
921""")
922
923def gen_type_maps_header(out):
924 """
925 Generate various header file declarations for type maps
926 @param out The file handle to write to
927 """
928
929 out.write("""
930/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700931 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700932 * top level message: Action, instruction, error, stats, queue_props, oxm
933 */
934#define OF_EXPERIMENTER_TYPE 0xffff
935""")
936 gen_type_to_obj_map_functions(out)
937 gen_obj_to_type_map_functions(out)
938
Rich Laneb157b0f2013-03-27 13:55:28 -0700939 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700940 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700941
942 out.write("""
943/**
944 * Map a message in a wire buffer object to its OF object id.
945 * @param wbuf Pointer to a wire buffer object, populated with an OF message
946 * @returns The object ID of the message
947 * @returns OF_OBJECT_INVALID if unable to parse the message type
948 */
949
950static inline of_object_id_t
951of_wire_object_id_get(of_wire_buffer_t *wbuf)
952{
953 of_message_t msg;
954
955 msg = (of_message_t)WBUF_BUF(wbuf);
956 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
957}
958
959/**
960 * Use the type/length from the wire buffer and init the object
961 * @param obj The object being initialized
962 * @param base_object_id If > 0, this indicates the base object
963 * @param max_len If > 0, the max length to expect for the obj
964 * type for inheritance checking
965 * @return OF_ERROR_
966 *
967 * Used for inheritance type objects such as actions and OXMs
968 * The type is checked and if valid, the object is initialized.
969 * Then the length is taken from the buffer.
970 *
971 * Note that the object version must already be properly set.
972 */
973static inline int
974of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
975 int max_len)
976{
977 if (obj->wire_type_get != NULL) {
978 of_object_id_t id;
979 obj->wire_type_get(obj, &id);
980 if (!of_wire_id_valid(id, base_object_id)) {
981 return OF_ERROR_PARSE;
982 }
983 obj->object_id = id;
984 /* Call the init function for this object type; do not push to wire */
985 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
986 }
987 if (obj->wire_length_get != NULL) {
988 int length;
989 obj->wire_length_get(obj, &length);
990 if (length < 0 || (max_len > 0 && length > max_len)) {
991 return OF_ERROR_PARSE;
992 }
993 obj->length = length;
994 } else {
995 /* @fixme Does this cover everything else? */
996 obj->length = of_object_fixed_len[obj->version][base_object_id];
997 }
998
999 return OF_ERROR_NONE;
1000}
1001
1002""")
1003
1004 # Generate the function that sets the object type fields
1005 out.write("""
1006
1007/**
1008 * Map a message in a wire buffer object to its OF object id.
1009 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1010 * @returns The object ID of the message
1011 * @returns OF_OBJECT_INVALID if unable to parse the message type
1012 *
1013 * Version must be set in the buffer prior to calling this routine
1014 */
1015
1016static inline int
1017of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
1018{
1019 int type;
1020 of_version_t ver;
1021 of_message_t msg;
1022
1023 msg = (of_message_t)WBUF_BUF(wbuf);
1024
1025 ver = of_message_version_get(msg);
1026
1027 /* ASSERT(id is a message object) */
1028
1029 if ((type = of_object_to_wire_type(id, ver)) < 0) {
1030 return OF_ERROR_PARAM;
1031 }
1032 of_message_type_set(msg, type);
1033
1034 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
1035 /* It's a stats obj */
1036 of_message_stats_type_set(msg, type);
1037 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001038 if ((type = of_object_to_error_type(id, ver)) >= 0) {
Rob Vaterlausb5e8c832013-10-04 12:50:23 -07001039 /* It's an error obj */
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001040 of_message_error_type_set(msg, type);
1041 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001042 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
1043 /* It's a flow mod obj */
1044 of_message_flow_mod_command_set(msg, ver, type);
1045 }
1046 if (of_object_id_is_extension(id, ver)) {
1047 uint32_t val32;
1048
1049 /* Set the experimenter and subtype codes */
1050 val32 = of_extension_to_experimenter_id(id, ver);
1051 of_message_experimenter_id_set(msg, val32);
1052 val32 = of_extension_to_experimenter_subtype(id, ver);
1053 of_message_experimenter_subtype_set(msg, val32);
1054 }
1055
1056 return OF_ERROR_NONE;
1057}
1058""")
1059
1060def gen_type_data_header(out):
1061
1062 out.write("""
1063/****************************************************************
1064 *
1065 * The following declarations are for type and length calculations.
1066 * Implementations may be found in of_type_maps.c
1067 *
1068 ****************************************************************/
1069/*
1070 * Special case length functions for objects with
1071 */
1072""")
1073 for ((cls, name), prev) in of_g.special_offsets.items():
1074 s_cls = cls[3:] # take off of_
1075 out.write("""
1076/**
1077 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001078 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001079 * length of %(name)s
1080 * @param bytes[out] Where to store the calculated length
1081 *
1082 * Preceding data member is %(prev)s.
1083 */
1084extern int of_length_%(s_cls)s_%(name)s_get(
1085 %(cls)s_t *obj, int *bytes);
1086
1087/**
1088 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001089 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001090 * length of %(name)s
1091 * @param offset[out] Where to store the calculated length
1092 *
1093 * Preceding data member is %(prev)s.
1094 */
1095extern int of_offset_%(s_cls)s_%(name)s_get(
1096 %(cls)s_t *obj, int *offset);
1097""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1098
1099# NOT NEEDED YET
1100# # For non-message, variable length objects, give a fun that
1101# # calculates the length
1102# for cls in of_g.standard_class_order:
1103# s_cls = cls[3:] # take off of_
1104# if !type_is_var_len(cls, version):
1105# continue
1106# out.write("""
1107# /**
1108# * Special length calculation for variable length object %(cls)s
1109# * @param obj An object of type %(cls)s whose length is being calculated
1110# * @param bytes[out] Where to store the calculated length
1111# *
1112# * The assumption is that the length member of the object is not
1113# * valid and the length needs to be calculated from other information
1114# * such as the parent.
1115# */
1116# extern int of_length_%(s_cls)s_get(
1117# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001118# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001119
1120 out.write("""
1121/****************************************************************
1122 * Wire type/length functions.
1123 ****************************************************************/
1124
1125extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1126extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1127
1128extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1129extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1130extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1131extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1132
1133extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1134extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1135
1136extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1137
1138/* Wire length is uint16 at front of structure */
1139extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1140extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1141
1142extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1143extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001144extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001145 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001146extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001147 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001148extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001149 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001150extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001151 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001152extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001153 of_object_id_t *id);
1154
Rich Lane47085722013-07-12 16:27:04 -07001155#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001156#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001157 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001158
1159extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1160extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1161
1162extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1163 int *bytes);
1164extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1165extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1166extern int of_extension_object_wire_push(of_object_t *obj);
1167
1168""")
1169
1170
1171def gen_length_array(out):
1172 """
1173 Generate an array giving the lengths of all objects/versions
1174 @param out The file handle to which to write
1175 """
1176 out.write("""
1177/**
1178 * An array with the number of bytes in the fixed length part
1179 * of each OF object
1180 */
1181""")
1182
1183 for version in of_g.of_version_range:
1184 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001185static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001186 -1, /* of_object is not instantiable */
1187""" % version)
1188 for i, cls in enumerate(of_g.all_class_order):
1189 comma = ","
1190 if i == len(of_g.all_class_order) - 1:
1191 comma = ""
1192 val = "-1" + comma
1193 if (cls, version) in of_g.base_length:
1194 val = str(of_g.base_length[(cls, version)]) + comma
1195 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1196 out.write("};\n")
1197
1198 out.write("""
1199/**
1200 * Unified map of fixed length part of each object
1201 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001202const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001203 NULL,
1204""")
1205 for version in of_g.of_version_range:
1206 out.write(" of_object_fixed_len_v%d,\n" % version)
1207 out.write("""
1208};
1209""")
1210
Andreas Wundsam53256162013-05-02 14:05:53 -07001211
Rich Lanef70be942013-07-18 13:33:14 -07001212def gen_extra_length_array(out):
1213 """
1214 Generate an array giving the extra lengths of all objects/versions
1215 @param out The file handle to which to write
1216 """
1217 out.write("""
1218/**
1219 * An array with the number of bytes in the extra length part
1220 * of each OF object
1221 */
1222""")
1223
1224 for version in of_g.of_version_range:
1225 out.write("""
1226static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1227 -1, /* of_object is not instantiable */
1228""" % version)
1229 for i, cls in enumerate(of_g.all_class_order):
1230 comma = ","
1231 if i == len(of_g.all_class_order) - 1:
1232 comma = ""
1233 val = "-1" + comma
1234 if (cls, version) in of_g.base_length:
1235 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1236 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1237 out.write("};\n")
1238
1239 out.write("""
1240/**
1241 * Unified map of extra length part of each object
1242 */
1243const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1244 NULL,
1245""")
1246 for version in of_g.of_version_range:
1247 out.write(" of_object_extra_len_v%d,\n" % version)
1248 out.write("""
1249};
1250""")
1251
1252
Rich Lanea06d0c32013-03-25 08:52:03 -07001253################################################################
1254################################################################
1255
1256# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1257def gen_object_id_to_stats_type(out):
1258 out.write("""
1259/**
1260 * Map from message object ID to stats type
1261 *
1262 * All message object IDs are mapped for simplicity
1263 */
1264""")
1265 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001266 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001267 out.write(" -1, /* of_object (invalid) */\n");
1268 for cls in of_g.ordered_messages:
1269 name = cls[3:]
1270 name = name[:name.find("_stats")]
1271 if (((cls in type_maps.stats_reply_list) or
1272 (cls in type_maps.stats_request_list)) and
1273 name in type_maps.stats_types[i]):
1274 out.write(" %d, /* %s */\n" %
1275 (type_maps.stats_types[i][name], cls))
1276 else:
1277 out.write(" -1, /* %s (invalid) */\n" % cls)
1278 out.write("};\n\n")
1279
1280 out.write("""
1281/**
1282 * Unified map, indexed by wire version which is 1-based.
1283 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001284const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001285 NULL,
1286""")
1287 for version in of_g.of_version_range:
1288 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1289 out.write("""
1290};
1291""")
1292