blob: 3c523b444a81bddce206905d168f2cd6f86efcbf [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))
70 elif cls in type_maps.flow_mod_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070071 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070072 (type_maps.type_val[("of_flow_mod", version)],
73 comma, cls))
74 elif (cls, version) in type_maps.type_val:
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[(cls, version)], comma, cls))
77 elif type_maps.message_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070078 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070079 (type_maps.type_val[("of_experimenter", version)],
80 comma, cls))
81 elif type_maps.action_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_action_experimenter",
84 version)],
85 comma, cls))
86 elif type_maps.action_id_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_action_id_experimenter",
89 version)],
90 comma, cls))
91 elif type_maps.instruction_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070092 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070093 (type_maps.type_val[("of_instruction_experimenter",
94 version)],
95 comma, cls))
96 elif type_maps.queue_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070097 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070098 (type_maps.type_val[("of_queue_prop_experimenter",
99 version)],
100 comma, cls))
101 elif type_maps.table_feature_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700102 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700103 (type_maps.type_val[("of_table_feature_prop_experimenter",
104 version)],
105 comma, cls))
106 else:
107 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
108 out.write("};\n\n")
109
110 out.write("""
111/**
112 * Unified map, indexed by wire version which is 1-based.
113 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700114const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700115 NULL,
116""")
117 for version in of_g.of_version_range:
118 out.write(" of_object_to_type_map_v%d,\n" % version)
119 out.write("""
120};
121""")
122
123def gen_object_id_to_extension_data(out):
124 out.write("""
125/**
126 * Extension data.
127 * @fixme There must be a better way to represent this data
128 */
129""")
130 for version in of_g.of_version_range:
131 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700132static const of_experimenter_data_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700133of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
134""" % version)
135 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
136 for j, cls in enumerate(of_g.all_class_order):
137 comma = ""
138 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
139 comma = ","
140
141 if type_maps.class_is_extension(cls, version):
142 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
143 subtype = type_maps.extension_to_subtype(cls, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700144 out.write(" {1, %s, %d}%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700145 (exp_name, subtype, comma, cls))
146 else:
147 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
148 (comma, cls))
149 out.write("};\n\n")
150
151 out.write("""
152/**
153 * Unified map, indexed by wire version which is 1-based.
154 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700155const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 NULL,
157""")
158 for version in of_g.of_version_range:
159 out.write(" of_object_to_extension_data_v%d,\n" % version)
160 out.write("""
161};
162""")
163
164def gen_type_to_object_id(out, type_str, prefix, template,
165 value_array, max_val):
166 """
167 Generate C maps from various message class groups to object ids
168
169 For each version, create an array mapping the type info to the
170 object ID. Then define an array containing those pointers.
171 """
172
173 # Create unified arrays and get length
174 arr_len = type_maps.type_array_len(value_array, max_val)
175 all_ars = []
176 for version, val_dict in value_array.items(): # Per version dict
177 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
178 all_ars.append(ar)
179
180 len_name = "%s_ITEM_COUNT" % prefix
181
182 for i, ar in enumerate(all_ars):
183 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -0700184 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700185 (type_str, version, len_name))
186 for i in range(arr_len):
187 comma = ""
188 if i < arr_len - 1: # Avoid ultimate comma
189 comma = ","
190
191 # Per-version length check
192 if i < len(ar):
193 v = ar[i]
194 else:
195 v = type_maps.invalid_type
196
197 if v == type_maps.invalid_type:
198 out.write(" %-30s /* %d (Invalid) */\n" %
199 ("OF_OBJECT_INVALID" + comma, i))
200 else:
201 name = (template % v.upper()) + comma
202 out.write(" %-30s /* %d */\n" % (name, i))
203 out.write("};\n")
204
205 out.write("""
206/**
207 * Maps from %(c_name)s wire type values to LOCI object ids
208 *
209 * Indexed by wire version which is 1-based.
210 */
211
Rich Laneb157b0f2013-03-27 13:55:28 -0700212const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700213 NULL,
214""" % dict(name=type_str, c_name=prefix.lower()))
215 for version in of_g.of_version_range:
216 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
217 version=version))
218 out.write("""
219};
220
Andreas Wundsam53256162013-05-02 14:05:53 -0700221""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700222 max_val=max_val, c_name=prefix.lower()))
223
224def gen_type_maps(out):
225 """
226 Generate various type maps
227 @param out The file handle to write to
228 """
229
230 out.write("#include <loci/loci.h>\n\n")
231
232 # Generate maps from wire type values to object IDs
233 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
234 "OF_ACTION_%s", type_maps.action_types,
235 max_type_value)
236 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
237 "OF_ACTION_ID_%s", type_maps.action_id_types,
238 max_type_value)
239 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700240 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700241 max_type_value)
242 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
243 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
244 max_type_value)
245 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
246 "OF_TABLE_FEATURE_PROP",
247 "OF_TABLE_FEATURE_PROP_%s",
248 type_maps.table_feature_prop_types,
249 max_type_value)
250 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
251 "OF_METER_BAND_%s", type_maps.meter_band_types,
252 max_type_value)
253 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
254 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
255 max_type_value)
256
257 # FIXME: Multipart re-organization
258 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
259 "OF_%s_STATS_REQUEST", type_maps.stats_types,
260 max_type_value)
261 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
262 "OF_%s_STATS_REPLY", type_maps.stats_types,
263 max_type_value)
264 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
265 "OF_FLOW_%s", type_maps.flow_mod_types,
266 max_type_value)
267 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
268 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
269 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
270 "OF_%s", type_maps.message_types, max_type_value)
271
272 gen_object_id_to_type(out)
273 gen_object_id_to_extension_data(out)
274 # Don't need array mapping ID to stats types right now; handled directly
275 # gen_object_id_to_stats_type(out)
276
277
278def gen_type_to_obj_map_functions(out):
279 """
280 Generate the templated static inline type map functions
281 @param out The file handle to write to
282 """
283
284 ################################################################
285 # Generate all type-to-object-ID maps in a common way
286 ################################################################
287 map_template = """
288/**
289 * %(name)s wire type to object ID array.
290 * Treat as private; use function accessor below
291 */
292
Rich Laneb157b0f2013-03-27 13:55:28 -0700293extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700294
295#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
296
297/**
298 * Map an %(name)s wire value to an OF object
299 * @param %(name)s The %(name)s type wire value
300 * @param version The version associated with the check
301 * @return The %(name)s OF object type
302 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700303 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700304 */
305static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700306of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700307{
308 if (!OF_VERSION_OKAY(version)) {
309 return OF_OBJECT_INVALID;
310 }
311 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
312 return OF_OBJECT_INVALID;
313 }
314
315 return of_%(name)s_type_to_id[version][%(name)s];
316}
317"""
318 map_with_experimenter_template = """
319/**
320 * %(name)s wire type to object ID array.
321 * Treat as private; use function accessor below
322 */
323
Rich Laneb157b0f2013-03-27 13:55:28 -0700324extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700325
326#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
327
328/**
329 * Map an %(name)s wire value to an OF object
330 * @param %(name)s The %(name)s type wire value
331 * @param version The version associated with the check
332 * @return The %(name)s OF object type
333 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700334 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700335 */
336static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700337of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700338{
339 if (!OF_VERSION_OKAY(version)) {
340 return OF_OBJECT_INVALID;
341 }
342 if (%(name)s == OF_EXPERIMENTER_TYPE) {
343 return OF_%(u_name)s_EXPERIMENTER;
344 }
345 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
346 return OF_OBJECT_INVALID;
347 }
348
349 return of_%(name)s_type_to_id[version][%(name)s];
350}
351"""
352
353 stats_template = """
354/**
355 * %(name)s wire type to object ID array.
356 * Treat as private; use function accessor below
357 */
358
Rich Laneb157b0f2013-03-27 13:55:28 -0700359extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700360
361#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
362
363/**
364 * Map an %(name)s wire value to an OF object
365 * @param %(name)s The %(name)s type wire value
366 * @param version The version associated with the check
367 * @return The %(name)s OF object type
368 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700369 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700370 */
371static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700372of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700373{
374 if (!OF_VERSION_OKAY(version)) {
375 return OF_OBJECT_INVALID;
376 }
377 if (%(name)s == OF_EXPERIMENTER_TYPE) {
378 return OF_EXPERIMENTER_%(u_name)s;
379 }
380 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
381 return OF_OBJECT_INVALID;
382 }
383
384 return of_%(name)s_type_to_id[version][%(name)s];
385}
386"""
387 # Experimenter mapping functions
388 # Currently we support very few candidates, so we just do a
389 # list of if/elses
390 experimenter_function = """
391/**
392 * @brief Map a message known to be an exp msg to the proper object
393 *
394 * Assume that the message is a vendor/experimenter message. Determine
395 * the specific object type for the message.
396 * @param msg An OF message object (uint8_t *)
397 * @param length The number of bytes in the message (for error checking)
398 * @param version Version of message
399 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
400 *
401 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
402 */
403
404static inline of_object_id_t
405of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
406 uint32_t experimenter_id;
407 uint32_t subtype;
408
409 /* Extract experimenter and subtype value; look for match from type maps */
410 experimenter_id = of_message_experimenter_id_get(msg);
411 subtype = of_message_experimenter_subtype_get(msg);
412
413 /* Do a simple if/else search for the ver, experimenter and subtype */
414"""
415 first = True
416 for version, experimenter_lists in type_maps.extension_message_subtype.items():
417 for exp, subtypes in experimenter_lists.items():
418 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700419 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700420 (version == %(ver_name)s)) {
421""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
422 for ext_msg, subtype in subtypes.items():
423 experimenter_function += """
424 if (subtype == %(subtype)s) {
425 return %(ext_msg)s;
426 }
427""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
428 experimenter_function += """
429 }
430"""
431 experimenter_function += """
432 return OF_EXPERIMENTER;
433}
434"""
435
436 # Message need different handling
437 msg_template = """
438/**
439 * %(name)s wire type to object ID array.
440 * Treat as private; use function accessor below
441 */
442
Rich Laneb157b0f2013-03-27 13:55:28 -0700443extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700444
445#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
446
447/**
448 * Extract the type info from the message and determine its object type
449 * @param msg An OF message object (uint8_t *)
450 * @param length The number of bytes in the message (for error checking)
451 * @returns object ID or OF_OBJECT_INVALID if parse error
452 */
453
454static inline of_object_id_t
455of_message_to_object_id(of_message_t msg, int length) {
456 uint8_t type;
457 of_version_t ver;
458 of_object_id_t obj_id;
459 uint16_t stats_type;
460 uint8_t flow_mod_cmd;
461
462 if (length < OF_MESSAGE_MIN_LENGTH) {
463 return OF_OBJECT_INVALID;
464 }
465 type = of_message_type_get(msg);
466 ver = of_message_version_get(msg);
467 if (!OF_VERSION_OKAY(ver)) {
468 return OF_OBJECT_INVALID;
469 }
470
471 if (type >= OF_MESSAGE_ITEM_COUNT) {
472 return OF_OBJECT_INVALID;
473 }
474
475 obj_id = of_message_type_to_id[ver][type];
476
477 /* Remap to specific message if known */
478 if (obj_id == OF_EXPERIMENTER) {
479 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
480 return OF_OBJECT_INVALID;
481 }
482 return of_message_experimenter_to_object_id(msg, ver);
483 }
484
485 /* Remap to add/delete/strict version */
486 if (obj_id == OF_FLOW_MOD) {
487 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
488 return OF_OBJECT_INVALID;
489 }
490 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
491 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
492 }
493
494 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
495 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
496 return OF_OBJECT_INVALID;
497 }
498 stats_type = of_message_stats_type_get(msg);
499 if (obj_id == OF_STATS_REQUEST) {
500 obj_id = of_stats_request_to_object_id(stats_type, ver);
501 } else {
502 obj_id = of_stats_reply_to_object_id(stats_type, ver);
503 }
504 }
505
506 return obj_id;
507}
508"""
509
Rich Laned8d29c92013-09-24 13:46:42 -0700510 oxm_template = """
511/**
512 * oxm wire type to object ID array.
513 * Treat as private; use function accessor below
514 */
515
516extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
517
518#define OF_OXM_ITEM_COUNT %(ar_len)d\n
519
520/**
521 * Map an oxm wire value to an OF object
522 * @param oxm The oxm type wire value
523 * @param version The version associated with the check
524 * @return The oxm OF object type
525 * @return OF_OBJECT_INVALID if type does not map to an object
526 *
527 */
528static inline of_object_id_t
529of_oxm_to_object_id(uint32_t type_len, of_version_t version)
530{
531 if (!OF_VERSION_OKAY(version)) {
532 return OF_OBJECT_INVALID;
533 }
534
535 uint16_t class = (type_len >> 16) & 0xffff;
536 uint8_t masked_type = (type_len >> 8) & 0xff;
537
538 if (class == 0x8000) {
539 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
540 return OF_OBJECT_INVALID;
541 }
542
543 return of_oxm_type_to_id[version][masked_type];
544 } else if (class == 0x0003) {
545 switch (masked_type) {
546 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
547 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
548 default: return OF_OBJECT_INVALID;
549 }
550 } else {
551 return OF_OBJECT_INVALID;
552 }
553}
554"""
555
Rich Lanea06d0c32013-03-25 08:52:03 -0700556 # Action types array gen
557 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700558 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700559 dict(name="action", u_name="ACTION", ar_len=ar_len))
560
561 # Action ID types array gen
562 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700563 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700564 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
565
566 # Instruction types array gen
567 ar_len = type_maps.type_array_len(type_maps.instruction_types,
568 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700569 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
571
572 # Queue prop types array gen
573 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
574 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700575 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700576 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
577
578 # Table feature prop types array gen
579 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
580 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700581 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700582 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
583 ar_len=ar_len))
584
585 # Meter band types array gen
586 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
587 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700588 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700589 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
590
591 # Hello elem types array gen
592 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
593 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700594 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700595 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
596
597 # Stats types array gen
598 ar_len = type_maps.type_array_len(type_maps.stats_types,
599 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700600 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700601 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700602 out.write(stats_template %
603 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700604 ar_len=ar_len))
605
606 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700607 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700608 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
609
Rich Laned8d29c92013-09-24 13:46:42 -0700610 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700611 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
612 out.write("""
613/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
614""")
Rich Laned8d29c92013-09-24 13:46:42 -0700615 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700616
Rich Laned8d29c92013-09-24 13:46:42 -0700617 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700618 out.write(experimenter_function)
619 # Must follow stats reply/request
620 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700621 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700622 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
623
624def gen_obj_to_type_map_functions(out):
625 """
626 Generate the static line maps from object IDs to types
627 @param out The file handle to write to
628 """
629
630 ################################################################
631 # Generate object ID to primary type map
632 ################################################################
633
634 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700635extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700636
637/**
638 * Map an object ID to its primary wire type value
639 * @param id An object ID
640 * @return For message objects, the type value in the OpenFlow header
641 * @return For non-message objects such as actions, instructions, OXMs
642 * returns the type value that appears in the respective sub-header
643 * @return -1 For improper version or out of bounds input
644 *
645 * NOTE that for stats request/reply, returns the header type, not the
646 * sub-type
647 *
648 * Also, note that the value is returned as a signed integer. So -1 is
649 * an error code, while 0xffff is the usual "experimenter" code.
650 */
651static inline int
652of_object_to_wire_type(of_object_id_t id, of_version_t version)
653{
654 if (!OF_VERSION_OKAY(version)) {
655 return -1;
656 }
657 if (id < 0 || id >= OF_OBJECT_COUNT) {
658 return -1;
659 }
660 return of_object_to_type_map[version][id];
661}
662
663""")
664
665 # Now for experimenter ids
666 out.write("""
667/**
668 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
669 */
670""")
671 out.write("""
672typedef struct of_experimenter_data_s {
673 int is_extension; /* Boolean indication that this is an extension */
674 uint32_t experimenter_id;
675 uint32_t subtype;
676} of_experimenter_data_t;
677
678""")
679
680 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700681extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700682
683/**
684 * Map from the object ID of an extension to the experimenter ID
685 */
686static inline uint32_t
687of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
688{
689 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
690 return (uint32_t) -1;
691 }
692 /* @fixme: Verify ver? */
693 return of_object_to_extension_data[ver][obj_id].experimenter_id;
694}
695
696/**
697 * Map from the object ID of an extension to the experimenter subtype
698 */
699static inline uint32_t
700of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
701{
702 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
703 return (uint32_t) -1;
704 }
705 /* @fixme: Verify ver? */
706 return of_object_to_extension_data[ver][obj_id].subtype;
707}
708
709/**
710 * Boolean function indicating the the given object ID/version
711 * is recognized as a supported (decode-able) extension.
712 */
713static inline int
714of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
715{
716 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
717 return (uint32_t) -1;
718 }
719 /* @fixme: Verify ver? */
720 return of_object_to_extension_data[ver][obj_id].is_extension;
721}
722""")
723
724 ################################################################
725 # Generate object ID to the stats sub-type map
726 ################################################################
727
728 out.write("""
729/**
730 * Map an object ID to a stats type
731 * @param id An object ID
732 * @return The wire value for the stats type
733 * @return -1 if not supported for this version
734 * @return -1 if id is not a specific stats type ID
735 *
736 * Note that the value is returned as a signed integer. So -1 is
737 * an error code, while 0xffff is the usual "experimenter" code.
738 */
739
740static inline int
741of_object_to_stats_type(of_object_id_t id, of_version_t version)
742{
743 if (!OF_VERSION_OKAY(version)) {
744 return -1;
745 }
746 switch (id) {
747""")
748 # Assumes 1.2 contains all stats types and type values are
749 # the same across all versions
750 stats_names = dict()
751 for ver in of_g.of_version_range:
752 for name, value in type_maps.stats_types[ver].items():
753 if name in stats_names and (not value == stats_names[name]):
754 print "ERROR stats type differ violating assumption"
755 sys.exit(1)
756 stats_names[name] = value
757
758 for name, value in stats_names.items():
759 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
760 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
761 for version in of_g.of_version_range:
762 if not name in type_maps.stats_types[version]:
763 out.write(" if (version == %s) break;\n" %
764 of_g.of_version_wire2name[version])
765 out.write(" return %d;\n" % value)
766 out.write("""
767 default:
768 break;
769 }
770 return -1; /* Not recognized as stats type object for this version */
771}
772""")
773
774 ################################################################
775 # Generate object ID to the flow mod sub-type map
776 ################################################################
777
778 out.write("""
779/**
780 * Map an object ID to a flow-mod command value
781 * @param id An object ID
782 * @return The wire value for the flow-mod command
783 * @return -1 if not supported for this version
784 * @return -1 if id is not a specific stats type ID
785 *
786 * Note that the value is returned as a signed integer. So -1 is
787 * an error code, while 0xffff is the usual "experimenter" code.
788 */
789
790static inline int
791of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
792{
793 if (!OF_VERSION_OKAY(version)) {
794 return -1;
795 }
796 switch (id) {
797""")
798 # Assumes 1.2 contains all stats types and type values are
799 # the same across all versions
800 flow_mod_names = dict()
801 for ver in of_g.of_version_range:
802 for name, value in type_maps.flow_mod_types[ver].items():
803 if name in flow_mod_names and \
804 (not value == flow_mod_names[name]):
805 print "ERROR flow mod command differ violating assumption"
806 sys.exit(1)
807 flow_mod_names[name] = value
808
809 for name, value in flow_mod_names.items():
810 out.write(" case OF_FLOW_%s:\n" % name.upper())
811 for version in of_g.of_version_range:
812 if not name in type_maps.flow_mod_types[version]:
813 out.write(" if (version == %s) break;\n" %
814 of_g.of_version_wire2name[version])
815 out.write(" return %d;\n" % value)
816 out.write("""
817 default:
818 break;
819 }
820 return -1; /* Not recognized as flow mod type object for this version */
821}
822
823""")
824
825def gen_type_maps_header(out):
826 """
827 Generate various header file declarations for type maps
828 @param out The file handle to write to
829 """
830
831 out.write("""
832/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700833 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700834 * top level message: Action, instruction, error, stats, queue_props, oxm
835 */
836#define OF_EXPERIMENTER_TYPE 0xffff
837""")
838 gen_type_to_obj_map_functions(out)
839 gen_obj_to_type_map_functions(out)
840
Rich Laneb157b0f2013-03-27 13:55:28 -0700841 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700842 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700843
844 out.write("""
845/**
846 * Map a message in a wire buffer object to its OF object id.
847 * @param wbuf Pointer to a wire buffer object, populated with an OF message
848 * @returns The object ID of the message
849 * @returns OF_OBJECT_INVALID if unable to parse the message type
850 */
851
852static inline of_object_id_t
853of_wire_object_id_get(of_wire_buffer_t *wbuf)
854{
855 of_message_t msg;
856
857 msg = (of_message_t)WBUF_BUF(wbuf);
858 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
859}
860
861/**
862 * Use the type/length from the wire buffer and init the object
863 * @param obj The object being initialized
864 * @param base_object_id If > 0, this indicates the base object
865 * @param max_len If > 0, the max length to expect for the obj
866 * type for inheritance checking
867 * @return OF_ERROR_
868 *
869 * Used for inheritance type objects such as actions and OXMs
870 * The type is checked and if valid, the object is initialized.
871 * Then the length is taken from the buffer.
872 *
873 * Note that the object version must already be properly set.
874 */
875static inline int
876of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
877 int max_len)
878{
879 if (obj->wire_type_get != NULL) {
880 of_object_id_t id;
881 obj->wire_type_get(obj, &id);
882 if (!of_wire_id_valid(id, base_object_id)) {
883 return OF_ERROR_PARSE;
884 }
885 obj->object_id = id;
886 /* Call the init function for this object type; do not push to wire */
887 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
888 }
889 if (obj->wire_length_get != NULL) {
890 int length;
891 obj->wire_length_get(obj, &length);
892 if (length < 0 || (max_len > 0 && length > max_len)) {
893 return OF_ERROR_PARSE;
894 }
895 obj->length = length;
896 } else {
897 /* @fixme Does this cover everything else? */
898 obj->length = of_object_fixed_len[obj->version][base_object_id];
899 }
900
901 return OF_ERROR_NONE;
902}
903
904""")
905
906 # Generate the function that sets the object type fields
907 out.write("""
908
909/**
910 * Map a message in a wire buffer object to its OF object id.
911 * @param wbuf Pointer to a wire buffer object, populated with an OF message
912 * @returns The object ID of the message
913 * @returns OF_OBJECT_INVALID if unable to parse the message type
914 *
915 * Version must be set in the buffer prior to calling this routine
916 */
917
918static inline int
919of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
920{
921 int type;
922 of_version_t ver;
923 of_message_t msg;
924
925 msg = (of_message_t)WBUF_BUF(wbuf);
926
927 ver = of_message_version_get(msg);
928
929 /* ASSERT(id is a message object) */
930
931 if ((type = of_object_to_wire_type(id, ver)) < 0) {
932 return OF_ERROR_PARAM;
933 }
934 of_message_type_set(msg, type);
935
936 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
937 /* It's a stats obj */
938 of_message_stats_type_set(msg, type);
939 }
940 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
941 /* It's a flow mod obj */
942 of_message_flow_mod_command_set(msg, ver, type);
943 }
944 if (of_object_id_is_extension(id, ver)) {
945 uint32_t val32;
946
947 /* Set the experimenter and subtype codes */
948 val32 = of_extension_to_experimenter_id(id, ver);
949 of_message_experimenter_id_set(msg, val32);
950 val32 = of_extension_to_experimenter_subtype(id, ver);
951 of_message_experimenter_subtype_set(msg, val32);
952 }
953
954 return OF_ERROR_NONE;
955}
956""")
957
958def gen_type_data_header(out):
959
960 out.write("""
961/****************************************************************
962 *
963 * The following declarations are for type and length calculations.
964 * Implementations may be found in of_type_maps.c
965 *
966 ****************************************************************/
967/*
968 * Special case length functions for objects with
969 */
970""")
971 for ((cls, name), prev) in of_g.special_offsets.items():
972 s_cls = cls[3:] # take off of_
973 out.write("""
974/**
975 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700976 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700977 * length of %(name)s
978 * @param bytes[out] Where to store the calculated length
979 *
980 * Preceding data member is %(prev)s.
981 */
982extern int of_length_%(s_cls)s_%(name)s_get(
983 %(cls)s_t *obj, int *bytes);
984
985/**
986 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700987 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700988 * length of %(name)s
989 * @param offset[out] Where to store the calculated length
990 *
991 * Preceding data member is %(prev)s.
992 */
993extern int of_offset_%(s_cls)s_%(name)s_get(
994 %(cls)s_t *obj, int *offset);
995""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
996
997# NOT NEEDED YET
998# # For non-message, variable length objects, give a fun that
999# # calculates the length
1000# for cls in of_g.standard_class_order:
1001# s_cls = cls[3:] # take off of_
1002# if !type_is_var_len(cls, version):
1003# continue
1004# out.write("""
1005# /**
1006# * Special length calculation for variable length object %(cls)s
1007# * @param obj An object of type %(cls)s whose length is being calculated
1008# * @param bytes[out] Where to store the calculated length
1009# *
1010# * The assumption is that the length member of the object is not
1011# * valid and the length needs to be calculated from other information
1012# * such as the parent.
1013# */
1014# extern int of_length_%(s_cls)s_get(
1015# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001016# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001017
1018 out.write("""
1019/****************************************************************
1020 * Wire type/length functions.
1021 ****************************************************************/
1022
1023extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1024extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1025
1026extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1027extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1028extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1029extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1030
1031extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1032extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1033
1034extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1035
1036/* Wire length is uint16 at front of structure */
1037extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1038extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1039
1040extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1041extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001042extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001043 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001044extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001045 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001046extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001047 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001048extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001049 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001050extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001051 of_object_id_t *id);
1052
Rich Lane47085722013-07-12 16:27:04 -07001053#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001054#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001055 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001056
1057extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1058extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1059
1060extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1061 int *bytes);
1062extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1063extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1064extern int of_extension_object_wire_push(of_object_t *obj);
1065
1066""")
1067
1068
1069def gen_length_array(out):
1070 """
1071 Generate an array giving the lengths of all objects/versions
1072 @param out The file handle to which to write
1073 """
1074 out.write("""
1075/**
1076 * An array with the number of bytes in the fixed length part
1077 * of each OF object
1078 */
1079""")
1080
1081 for version in of_g.of_version_range:
1082 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001083static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001084 -1, /* of_object is not instantiable */
1085""" % version)
1086 for i, cls in enumerate(of_g.all_class_order):
1087 comma = ","
1088 if i == len(of_g.all_class_order) - 1:
1089 comma = ""
1090 val = "-1" + comma
1091 if (cls, version) in of_g.base_length:
1092 val = str(of_g.base_length[(cls, version)]) + comma
1093 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1094 out.write("};\n")
1095
1096 out.write("""
1097/**
1098 * Unified map of fixed length part of each object
1099 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001100const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001101 NULL,
1102""")
1103 for version in of_g.of_version_range:
1104 out.write(" of_object_fixed_len_v%d,\n" % version)
1105 out.write("""
1106};
1107""")
1108
Andreas Wundsam53256162013-05-02 14:05:53 -07001109
Rich Lanef70be942013-07-18 13:33:14 -07001110def gen_extra_length_array(out):
1111 """
1112 Generate an array giving the extra lengths of all objects/versions
1113 @param out The file handle to which to write
1114 """
1115 out.write("""
1116/**
1117 * An array with the number of bytes in the extra length part
1118 * of each OF object
1119 */
1120""")
1121
1122 for version in of_g.of_version_range:
1123 out.write("""
1124static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1125 -1, /* of_object is not instantiable */
1126""" % version)
1127 for i, cls in enumerate(of_g.all_class_order):
1128 comma = ","
1129 if i == len(of_g.all_class_order) - 1:
1130 comma = ""
1131 val = "-1" + comma
1132 if (cls, version) in of_g.base_length:
1133 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1134 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1135 out.write("};\n")
1136
1137 out.write("""
1138/**
1139 * Unified map of extra length part of each object
1140 */
1141const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1142 NULL,
1143""")
1144 for version in of_g.of_version_range:
1145 out.write(" of_object_extra_len_v%d,\n" % version)
1146 out.write("""
1147};
1148""")
1149
1150
Rich Lanea06d0c32013-03-25 08:52:03 -07001151################################################################
1152################################################################
1153
1154# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1155def gen_object_id_to_stats_type(out):
1156 out.write("""
1157/**
1158 * Map from message object ID to stats type
1159 *
1160 * All message object IDs are mapped for simplicity
1161 */
1162""")
1163 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001164 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001165 out.write(" -1, /* of_object (invalid) */\n");
1166 for cls in of_g.ordered_messages:
1167 name = cls[3:]
1168 name = name[:name.find("_stats")]
1169 if (((cls in type_maps.stats_reply_list) or
1170 (cls in type_maps.stats_request_list)) and
1171 name in type_maps.stats_types[i]):
1172 out.write(" %d, /* %s */\n" %
1173 (type_maps.stats_types[i][name], cls))
1174 else:
1175 out.write(" -1, /* %s (invalid) */\n" % cls)
1176 out.write("};\n\n")
1177
1178 out.write("""
1179/**
1180 * Unified map, indexed by wire version which is 1-based.
1181 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001182const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001183 NULL,
1184""")
1185 for version in of_g.of_version_range:
1186 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1187 out.write("""
1188};
1189""")
1190