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