blob: ab4b3e08d0d9d6d829606e0aac795b2662c37324 [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;
Rich Lane61718362013-10-24 16:59:42 -0700601 case 0x02: return OF_OXM_BSN_LAG_ID;
602 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700603 default: return OF_OBJECT_INVALID;
604 }
605 } else {
606 return OF_OBJECT_INVALID;
607 }
608}
609"""
610
Rich Lanea06d0c32013-03-25 08:52:03 -0700611 # Action types array gen
612 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700613 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700614 dict(name="action", u_name="ACTION", ar_len=ar_len))
615
616 # Action ID types array gen
617 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700618 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700619 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
620
621 # Instruction types array gen
622 ar_len = type_maps.type_array_len(type_maps.instruction_types,
623 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700624 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700625 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
626
627 # Queue prop types array gen
628 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
629 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700630 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700631 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
632
633 # Table feature prop types array gen
634 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
635 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700636 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700637 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
638 ar_len=ar_len))
639
640 # Meter band types array gen
641 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
642 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700643 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700644 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
645
646 # Hello elem types array gen
647 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
648 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700649 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700650 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
651
652 # Stats types array gen
653 ar_len = type_maps.type_array_len(type_maps.stats_types,
654 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700655 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700656 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700657 out.write(stats_template %
658 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700659 ar_len=ar_len))
660
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700661 ar_len = type_maps.type_array_len(type_maps.error_types,
662 max_type_value)
663 out.write(error_msg_template %
664 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
665# out.write(error_msg_function)
666
Rich Lanea06d0c32013-03-25 08:52:03 -0700667 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700668 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700669 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
670
Rich Laned8d29c92013-09-24 13:46:42 -0700671 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700672 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
673 out.write("""
674/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
675""")
Rich Laned8d29c92013-09-24 13:46:42 -0700676 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700677
Rich Laned8d29c92013-09-24 13:46:42 -0700678 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700679 out.write(experimenter_function)
680 # Must follow stats reply/request
681 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700682 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700683 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
684
685def gen_obj_to_type_map_functions(out):
686 """
687 Generate the static line maps from object IDs to types
688 @param out The file handle to write to
689 """
690
691 ################################################################
692 # Generate object ID to primary type map
693 ################################################################
694
695 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700696extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700697
698/**
699 * Map an object ID to its primary wire type value
700 * @param id An object ID
701 * @return For message objects, the type value in the OpenFlow header
702 * @return For non-message objects such as actions, instructions, OXMs
703 * returns the type value that appears in the respective sub-header
704 * @return -1 For improper version or out of bounds input
705 *
706 * NOTE that for stats request/reply, returns the header type, not the
707 * sub-type
708 *
709 * Also, note that the value is returned as a signed integer. So -1 is
710 * an error code, while 0xffff is the usual "experimenter" code.
711 */
712static inline int
713of_object_to_wire_type(of_object_id_t id, of_version_t version)
714{
715 if (!OF_VERSION_OKAY(version)) {
716 return -1;
717 }
718 if (id < 0 || id >= OF_OBJECT_COUNT) {
719 return -1;
720 }
721 return of_object_to_type_map[version][id];
722}
723
724""")
725
726 # Now for experimenter ids
727 out.write("""
728/**
729 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
730 */
731""")
732 out.write("""
733typedef struct of_experimenter_data_s {
734 int is_extension; /* Boolean indication that this is an extension */
735 uint32_t experimenter_id;
736 uint32_t subtype;
737} of_experimenter_data_t;
738
739""")
740
741 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700742extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700743
744/**
745 * Map from the object ID of an extension to the experimenter ID
746 */
747static inline uint32_t
748of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
749{
750 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
751 return (uint32_t) -1;
752 }
753 /* @fixme: Verify ver? */
754 return of_object_to_extension_data[ver][obj_id].experimenter_id;
755}
756
757/**
758 * Map from the object ID of an extension to the experimenter subtype
759 */
760static inline uint32_t
761of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
762{
763 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
764 return (uint32_t) -1;
765 }
766 /* @fixme: Verify ver? */
767 return of_object_to_extension_data[ver][obj_id].subtype;
768}
769
770/**
771 * Boolean function indicating the the given object ID/version
772 * is recognized as a supported (decode-able) extension.
773 */
774static inline int
775of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
776{
777 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
778 return (uint32_t) -1;
779 }
780 /* @fixme: Verify ver? */
781 return of_object_to_extension_data[ver][obj_id].is_extension;
782}
783""")
784
785 ################################################################
786 # Generate object ID to the stats sub-type map
787 ################################################################
788
789 out.write("""
790/**
791 * Map an object ID to a stats type
792 * @param id An object ID
793 * @return The wire value for the stats type
794 * @return -1 if not supported for this version
795 * @return -1 if id is not a specific stats type ID
796 *
797 * Note that the value is returned as a signed integer. So -1 is
798 * an error code, while 0xffff is the usual "experimenter" code.
799 */
800
801static inline int
802of_object_to_stats_type(of_object_id_t id, of_version_t version)
803{
804 if (!OF_VERSION_OKAY(version)) {
805 return -1;
806 }
807 switch (id) {
808""")
809 # Assumes 1.2 contains all stats types and type values are
810 # the same across all versions
811 stats_names = dict()
812 for ver in of_g.of_version_range:
813 for name, value in type_maps.stats_types[ver].items():
814 if name in stats_names and (not value == stats_names[name]):
815 print "ERROR stats type differ violating assumption"
816 sys.exit(1)
817 stats_names[name] = value
818
819 for name, value in stats_names.items():
820 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
821 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
822 for version in of_g.of_version_range:
823 if not name in type_maps.stats_types[version]:
824 out.write(" if (version == %s) break;\n" %
825 of_g.of_version_wire2name[version])
826 out.write(" return %d;\n" % value)
827 out.write("""
828 default:
829 break;
830 }
831 return -1; /* Not recognized as stats type object for this version */
832}
833""")
834
835 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700836 # Generate object ID to the error sub-type map
837 ################################################################
838 out.write("""
839/**
840 * Map an object ID to an error type
841 * @param id An object ID
842 * @return The wire value for the error type
843 * @return -1 if not supported for this version
844 * @return -1 if id is not a specific error type ID
845 *
846 * Note that the value is returned as a signed integer. So -1 is
847 * an error code, while 0xffff is the usual "experimenter" code.
848 */
849
850static inline int
851of_object_to_error_type(of_object_id_t id, of_version_t version)
852{
853 if (!OF_VERSION_OKAY(version)) {
854 return -1;
855 }
856 switch (id) {""")
857 error_names = set()
858 for ver in of_g.of_version_range:
859 for name in type_maps.error_types[ver]:
860 error_names.add(name)
861 for name in error_names:
862 out.write("""
863 case OF_%(name)s_ERROR_MSG:
864 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
865 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
866 break;""" % {"name": name.upper()})
867 out.write("""
868 default:
869 break;
870 }
871 return -1; /* Not recognized as error type object for this version */
872}
873""")
874
875 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700876 # Generate object ID to the flow mod sub-type map
877 ################################################################
878
879 out.write("""
880/**
881 * Map an object ID to a flow-mod command value
882 * @param id An object ID
883 * @return The wire value for the flow-mod command
884 * @return -1 if not supported for this version
885 * @return -1 if id is not a specific stats type ID
886 *
887 * Note that the value is returned as a signed integer. So -1 is
888 * an error code, while 0xffff is the usual "experimenter" code.
889 */
890
891static inline int
892of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
893{
894 if (!OF_VERSION_OKAY(version)) {
895 return -1;
896 }
897 switch (id) {
898""")
899 # Assumes 1.2 contains all stats types and type values are
900 # the same across all versions
901 flow_mod_names = dict()
902 for ver in of_g.of_version_range:
903 for name, value in type_maps.flow_mod_types[ver].items():
904 if name in flow_mod_names and \
905 (not value == flow_mod_names[name]):
906 print "ERROR flow mod command differ violating assumption"
907 sys.exit(1)
908 flow_mod_names[name] = value
909
910 for name, value in flow_mod_names.items():
911 out.write(" case OF_FLOW_%s:\n" % name.upper())
912 for version in of_g.of_version_range:
913 if not name in type_maps.flow_mod_types[version]:
914 out.write(" if (version == %s) break;\n" %
915 of_g.of_version_wire2name[version])
916 out.write(" return %d;\n" % value)
917 out.write("""
918 default:
919 break;
920 }
921 return -1; /* Not recognized as flow mod type object for this version */
922}
923
924""")
925
926def gen_type_maps_header(out):
927 """
928 Generate various header file declarations for type maps
929 @param out The file handle to write to
930 """
931
932 out.write("""
933/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700934 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 * top level message: Action, instruction, error, stats, queue_props, oxm
936 */
937#define OF_EXPERIMENTER_TYPE 0xffff
938""")
939 gen_type_to_obj_map_functions(out)
940 gen_obj_to_type_map_functions(out)
941
Rich Laneb157b0f2013-03-27 13:55:28 -0700942 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700943 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700944
945 out.write("""
946/**
947 * Map a message in a wire buffer object to its OF object id.
948 * @param wbuf Pointer to a wire buffer object, populated with an OF message
949 * @returns The object ID of the message
950 * @returns OF_OBJECT_INVALID if unable to parse the message type
951 */
952
953static inline of_object_id_t
954of_wire_object_id_get(of_wire_buffer_t *wbuf)
955{
956 of_message_t msg;
957
958 msg = (of_message_t)WBUF_BUF(wbuf);
959 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
960}
961
962/**
963 * Use the type/length from the wire buffer and init the object
964 * @param obj The object being initialized
965 * @param base_object_id If > 0, this indicates the base object
966 * @param max_len If > 0, the max length to expect for the obj
967 * type for inheritance checking
968 * @return OF_ERROR_
969 *
970 * Used for inheritance type objects such as actions and OXMs
971 * The type is checked and if valid, the object is initialized.
972 * Then the length is taken from the buffer.
973 *
974 * Note that the object version must already be properly set.
975 */
976static inline int
977of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
978 int max_len)
979{
980 if (obj->wire_type_get != NULL) {
981 of_object_id_t id;
982 obj->wire_type_get(obj, &id);
983 if (!of_wire_id_valid(id, base_object_id)) {
984 return OF_ERROR_PARSE;
985 }
986 obj->object_id = id;
987 /* Call the init function for this object type; do not push to wire */
988 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
989 }
990 if (obj->wire_length_get != NULL) {
991 int length;
992 obj->wire_length_get(obj, &length);
993 if (length < 0 || (max_len > 0 && length > max_len)) {
994 return OF_ERROR_PARSE;
995 }
996 obj->length = length;
997 } else {
998 /* @fixme Does this cover everything else? */
999 obj->length = of_object_fixed_len[obj->version][base_object_id];
1000 }
1001
1002 return OF_ERROR_NONE;
1003}
1004
1005""")
1006
1007 # Generate the function that sets the object type fields
1008 out.write("""
1009
1010/**
1011 * Map a message in a wire buffer object to its OF object id.
1012 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1013 * @returns The object ID of the message
1014 * @returns OF_OBJECT_INVALID if unable to parse the message type
1015 *
1016 * Version must be set in the buffer prior to calling this routine
1017 */
1018
1019static inline int
1020of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
1021{
1022 int type;
1023 of_version_t ver;
1024 of_message_t msg;
1025
1026 msg = (of_message_t)WBUF_BUF(wbuf);
1027
1028 ver = of_message_version_get(msg);
1029
1030 /* ASSERT(id is a message object) */
1031
1032 if ((type = of_object_to_wire_type(id, ver)) < 0) {
1033 return OF_ERROR_PARAM;
1034 }
1035 of_message_type_set(msg, type);
1036
1037 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
1038 /* It's a stats obj */
1039 of_message_stats_type_set(msg, type);
1040 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001041 if ((type = of_object_to_error_type(id, ver)) >= 0) {
Rob Vaterlausb5e8c832013-10-04 12:50:23 -07001042 /* It's an error obj */
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001043 of_message_error_type_set(msg, type);
1044 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001045 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
1046 /* It's a flow mod obj */
1047 of_message_flow_mod_command_set(msg, ver, type);
1048 }
1049 if (of_object_id_is_extension(id, ver)) {
1050 uint32_t val32;
1051
1052 /* Set the experimenter and subtype codes */
1053 val32 = of_extension_to_experimenter_id(id, ver);
1054 of_message_experimenter_id_set(msg, val32);
1055 val32 = of_extension_to_experimenter_subtype(id, ver);
1056 of_message_experimenter_subtype_set(msg, val32);
1057 }
1058
1059 return OF_ERROR_NONE;
1060}
1061""")
1062
1063def gen_type_data_header(out):
1064
1065 out.write("""
1066/****************************************************************
1067 *
1068 * The following declarations are for type and length calculations.
1069 * Implementations may be found in of_type_maps.c
1070 *
1071 ****************************************************************/
1072/*
1073 * Special case length functions for objects with
1074 */
1075""")
1076 for ((cls, name), prev) in of_g.special_offsets.items():
1077 s_cls = cls[3:] # take off of_
1078 out.write("""
1079/**
1080 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001081 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001082 * length of %(name)s
1083 * @param bytes[out] Where to store the calculated length
1084 *
1085 * Preceding data member is %(prev)s.
1086 */
1087extern int of_length_%(s_cls)s_%(name)s_get(
1088 %(cls)s_t *obj, int *bytes);
1089
1090/**
1091 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001092 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001093 * length of %(name)s
1094 * @param offset[out] Where to store the calculated length
1095 *
1096 * Preceding data member is %(prev)s.
1097 */
1098extern int of_offset_%(s_cls)s_%(name)s_get(
1099 %(cls)s_t *obj, int *offset);
1100""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1101
1102# NOT NEEDED YET
1103# # For non-message, variable length objects, give a fun that
1104# # calculates the length
1105# for cls in of_g.standard_class_order:
1106# s_cls = cls[3:] # take off of_
1107# if !type_is_var_len(cls, version):
1108# continue
1109# out.write("""
1110# /**
1111# * Special length calculation for variable length object %(cls)s
1112# * @param obj An object of type %(cls)s whose length is being calculated
1113# * @param bytes[out] Where to store the calculated length
1114# *
1115# * The assumption is that the length member of the object is not
1116# * valid and the length needs to be calculated from other information
1117# * such as the parent.
1118# */
1119# extern int of_length_%(s_cls)s_get(
1120# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001121# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001122
1123 out.write("""
1124/****************************************************************
1125 * Wire type/length functions.
1126 ****************************************************************/
1127
1128extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1129extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1130
1131extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1132extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1133extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1134extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1135
1136extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1137extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1138
1139extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1140
1141/* Wire length is uint16 at front of structure */
1142extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1143extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1144
1145extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1146extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001147extern void of_instruction_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_queue_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_table_feature_prop_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_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001154 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001155extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001156 of_object_id_t *id);
1157
Rich Lane47085722013-07-12 16:27:04 -07001158#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001159#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001160 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001161
1162extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1163extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1164
1165extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1166 int *bytes);
1167extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1168extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1169extern int of_extension_object_wire_push(of_object_t *obj);
1170
1171""")
1172
1173
1174def gen_length_array(out):
1175 """
1176 Generate an array giving the lengths of all objects/versions
1177 @param out The file handle to which to write
1178 """
1179 out.write("""
1180/**
1181 * An array with the number of bytes in the fixed length part
1182 * of each OF object
1183 */
1184""")
1185
1186 for version in of_g.of_version_range:
1187 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001188static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001189 -1, /* of_object is not instantiable */
1190""" % version)
1191 for i, cls in enumerate(of_g.all_class_order):
1192 comma = ","
1193 if i == len(of_g.all_class_order) - 1:
1194 comma = ""
1195 val = "-1" + comma
1196 if (cls, version) in of_g.base_length:
1197 val = str(of_g.base_length[(cls, version)]) + comma
1198 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1199 out.write("};\n")
1200
1201 out.write("""
1202/**
1203 * Unified map of fixed length part of each object
1204 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001205const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001206 NULL,
1207""")
1208 for version in of_g.of_version_range:
1209 out.write(" of_object_fixed_len_v%d,\n" % version)
1210 out.write("""
1211};
1212""")
1213
Andreas Wundsam53256162013-05-02 14:05:53 -07001214
Rich Lanef70be942013-07-18 13:33:14 -07001215def gen_extra_length_array(out):
1216 """
1217 Generate an array giving the extra lengths of all objects/versions
1218 @param out The file handle to which to write
1219 """
1220 out.write("""
1221/**
1222 * An array with the number of bytes in the extra length part
1223 * of each OF object
1224 */
1225""")
1226
1227 for version in of_g.of_version_range:
1228 out.write("""
1229static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1230 -1, /* of_object is not instantiable */
1231""" % version)
1232 for i, cls in enumerate(of_g.all_class_order):
1233 comma = ","
1234 if i == len(of_g.all_class_order) - 1:
1235 comma = ""
1236 val = "-1" + comma
1237 if (cls, version) in of_g.base_length:
1238 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1239 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1240 out.write("};\n")
1241
1242 out.write("""
1243/**
1244 * Unified map of extra length part of each object
1245 */
1246const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1247 NULL,
1248""")
1249 for version in of_g.of_version_range:
1250 out.write(" of_object_extra_len_v%d,\n" % version)
1251 out.write("""
1252};
1253""")
1254
1255
Rich Lanea06d0c32013-03-25 08:52:03 -07001256################################################################
1257################################################################
1258
1259# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1260def gen_object_id_to_stats_type(out):
1261 out.write("""
1262/**
1263 * Map from message object ID to stats type
1264 *
1265 * All message object IDs are mapped for simplicity
1266 */
1267""")
1268 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001269 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001270 out.write(" -1, /* of_object (invalid) */\n");
1271 for cls in of_g.ordered_messages:
1272 name = cls[3:]
1273 name = name[:name.find("_stats")]
1274 if (((cls in type_maps.stats_reply_list) or
1275 (cls in type_maps.stats_request_list)) and
1276 name in type_maps.stats_types[i]):
1277 out.write(" %d, /* %s */\n" %
1278 (type_maps.stats_types[i][name], cls))
1279 else:
1280 out.write(" -1, /* %s (invalid) */\n" % cls)
1281 out.write("};\n\n")
1282
1283 out.write("""
1284/**
1285 * Unified map, indexed by wire version which is 1-based.
1286 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001287const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001288 NULL,
1289""")
1290 for version in of_g.of_version_range:
1291 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1292 out.write("""
1293};
1294""")
1295