blob: 69dc8045b144a4eff986b9d4e3f6eebe84a41659 [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 *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080035import c_gen.type_maps as type_maps
Rich Lanea06d0c32013-03-25 08:52:03 -070036
37
38# Some number larger than small type values, but less then
39# reserved values like 0xffff
40max_type_value = 1000
41
42def gen_object_id_to_type(out):
43 out.write("""
44/**
45 * Map from object ID to primary wire type
46 *
47 * For messages, this is the header type; in particular for stats, this is
48 * the common stats request/response type. For per-stats types, use the
49 * stats type map. For things like actions, instructions or queue-props,
50 * this gives the "sub type".
51 */
52""")
53 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -070054 out.write("static const int\nof_object_to_type_map_v%d[OF_OBJECT_COUNT] = {\n"
Rich Lanea06d0c32013-03-25 08:52:03 -070055 %version)
56 out.write(" -1, /* of_object, not a valid specific type */\n")
57 for j, cls in enumerate(of_g.all_class_order):
58 comma = ""
59 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
60 comma = ","
61
62 if cls in type_maps.stats_reply_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070063 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070064 (type_maps.type_val[("of_stats_reply", version)],
65 comma, cls))
66 elif cls in type_maps.stats_request_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070067 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070068 (type_maps.type_val[("of_stats_request", version)],
69 comma, cls))
Rob Vaterlausb3f49d92013-10-01 17:57:31 -070070 elif cls in type_maps.error_msg_list:
71 out.write(" %d%s /* %s */\n" %
72 (type_maps.type_val[("of_error_msg", version)],
73 comma, cls))
Rich Lanea06d0c32013-03-25 08:52:03 -070074 elif cls in type_maps.flow_mod_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070075 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070076 (type_maps.type_val[("of_flow_mod", version)],
77 comma, cls))
Rich 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 Laneeb21c4f2013-10-28 17:34:41 -0700603 case 0x04: return OF_OXM_BSN_VRF;
604 case 0x05: return OF_OXM_BSN_VRF_MASKED;
605 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
606 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
607 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
608 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
609 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
610 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
611 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
612 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700613 default: return OF_OBJECT_INVALID;
614 }
615 } else {
616 return OF_OBJECT_INVALID;
617 }
618}
619"""
620
Rich Lanea06d0c32013-03-25 08:52:03 -0700621 # Action types array gen
622 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700623 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700624 dict(name="action", u_name="ACTION", ar_len=ar_len))
625
626 # Action ID types array gen
627 ar_len = type_maps.type_array_len(type_maps.action_id_types, 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="action_id", u_name="ACTION_ID", ar_len=ar_len))
630
631 # Instruction types array gen
632 ar_len = type_maps.type_array_len(type_maps.instruction_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="instruction", u_name="INSTRUCTION", ar_len=ar_len))
636
637 # Queue prop types array gen
638 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
639 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700640 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700641 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
642
643 # Table feature prop types array gen
644 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
645 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700646 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700647 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
648 ar_len=ar_len))
649
650 # Meter band types array gen
651 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
652 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700653 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700654 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
655
656 # Hello elem types array gen
657 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
658 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700659 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700660 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
661
662 # Stats types array gen
663 ar_len = type_maps.type_array_len(type_maps.stats_types,
664 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700665 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700666 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700667 out.write(stats_template %
668 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700669 ar_len=ar_len))
670
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700671 ar_len = type_maps.type_array_len(type_maps.error_types,
672 max_type_value)
673 out.write(error_msg_template %
674 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
675# out.write(error_msg_function)
676
Rich Lanea06d0c32013-03-25 08:52:03 -0700677 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700678 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700679 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
680
Rich Laned8d29c92013-09-24 13:46:42 -0700681 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700682 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
683 out.write("""
684/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
685""")
Rich Laned8d29c92013-09-24 13:46:42 -0700686 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700687
Rich Laned8d29c92013-09-24 13:46:42 -0700688 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700689 out.write(experimenter_function)
690 # Must follow stats reply/request
691 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700692 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700693 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
694
695def gen_obj_to_type_map_functions(out):
696 """
697 Generate the static line maps from object IDs to types
698 @param out The file handle to write to
699 """
700
701 ################################################################
702 # Generate object ID to primary type map
703 ################################################################
704
705 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700706extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700707
708/**
709 * Map an object ID to its primary wire type value
710 * @param id An object ID
711 * @return For message objects, the type value in the OpenFlow header
712 * @return For non-message objects such as actions, instructions, OXMs
713 * returns the type value that appears in the respective sub-header
714 * @return -1 For improper version or out of bounds input
715 *
716 * NOTE that for stats request/reply, returns the header type, not the
717 * sub-type
718 *
719 * Also, note that the value is returned as a signed integer. So -1 is
720 * an error code, while 0xffff is the usual "experimenter" code.
721 */
722static inline int
723of_object_to_wire_type(of_object_id_t id, of_version_t version)
724{
725 if (!OF_VERSION_OKAY(version)) {
726 return -1;
727 }
728 if (id < 0 || id >= OF_OBJECT_COUNT) {
729 return -1;
730 }
731 return of_object_to_type_map[version][id];
732}
733
734""")
735
736 # Now for experimenter ids
737 out.write("""
738/**
739 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
740 */
741""")
742 out.write("""
743typedef struct of_experimenter_data_s {
744 int is_extension; /* Boolean indication that this is an extension */
745 uint32_t experimenter_id;
746 uint32_t subtype;
747} of_experimenter_data_t;
748
749""")
750
751 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700752extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700753
754/**
755 * Map from the object ID of an extension to the experimenter ID
756 */
757static inline uint32_t
758of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
759{
760 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
761 return (uint32_t) -1;
762 }
763 /* @fixme: Verify ver? */
764 return of_object_to_extension_data[ver][obj_id].experimenter_id;
765}
766
767/**
768 * Map from the object ID of an extension to the experimenter subtype
769 */
770static inline uint32_t
771of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
772{
773 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
774 return (uint32_t) -1;
775 }
776 /* @fixme: Verify ver? */
777 return of_object_to_extension_data[ver][obj_id].subtype;
778}
779
780/**
781 * Boolean function indicating the the given object ID/version
782 * is recognized as a supported (decode-able) extension.
783 */
784static inline int
785of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
786{
787 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
788 return (uint32_t) -1;
789 }
790 /* @fixme: Verify ver? */
791 return of_object_to_extension_data[ver][obj_id].is_extension;
792}
793""")
794
795 ################################################################
796 # Generate object ID to the stats sub-type map
797 ################################################################
798
799 out.write("""
800/**
801 * Map an object ID to a stats type
802 * @param id An object ID
803 * @return The wire value for the stats type
804 * @return -1 if not supported for this version
805 * @return -1 if id is not a specific stats type ID
806 *
807 * Note that the value is returned as a signed integer. So -1 is
808 * an error code, while 0xffff is the usual "experimenter" code.
809 */
810
811static inline int
812of_object_to_stats_type(of_object_id_t id, of_version_t version)
813{
814 if (!OF_VERSION_OKAY(version)) {
815 return -1;
816 }
817 switch (id) {
818""")
819 # Assumes 1.2 contains all stats types and type values are
820 # the same across all versions
821 stats_names = dict()
822 for ver in of_g.of_version_range:
823 for name, value in type_maps.stats_types[ver].items():
824 if name in stats_names and (not value == stats_names[name]):
825 print "ERROR stats type differ violating assumption"
826 sys.exit(1)
827 stats_names[name] = value
828
829 for name, value in stats_names.items():
830 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
831 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
832 for version in of_g.of_version_range:
833 if not name in type_maps.stats_types[version]:
834 out.write(" if (version == %s) break;\n" %
835 of_g.of_version_wire2name[version])
836 out.write(" return %d;\n" % value)
837 out.write("""
838 default:
839 break;
840 }
841 return -1; /* Not recognized as stats type object for this version */
842}
843""")
844
845 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700846 # Generate object ID to the error sub-type map
847 ################################################################
848 out.write("""
849/**
850 * Map an object ID to an error type
851 * @param id An object ID
852 * @return The wire value for the error type
853 * @return -1 if not supported for this version
854 * @return -1 if id is not a specific error type ID
855 *
856 * Note that the value is returned as a signed integer. So -1 is
857 * an error code, while 0xffff is the usual "experimenter" code.
858 */
859
860static inline int
861of_object_to_error_type(of_object_id_t id, of_version_t version)
862{
863 if (!OF_VERSION_OKAY(version)) {
864 return -1;
865 }
866 switch (id) {""")
867 error_names = set()
868 for ver in of_g.of_version_range:
869 for name in type_maps.error_types[ver]:
870 error_names.add(name)
871 for name in error_names:
872 out.write("""
873 case OF_%(name)s_ERROR_MSG:
874 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
875 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
876 break;""" % {"name": name.upper()})
877 out.write("""
878 default:
879 break;
880 }
881 return -1; /* Not recognized as error type object for this version */
882}
883""")
884
885 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700886 # Generate object ID to the flow mod sub-type map
887 ################################################################
888
889 out.write("""
890/**
891 * Map an object ID to a flow-mod command value
892 * @param id An object ID
893 * @return The wire value for the flow-mod command
894 * @return -1 if not supported for this version
895 * @return -1 if id is not a specific stats type ID
896 *
897 * Note that the value is returned as a signed integer. So -1 is
898 * an error code, while 0xffff is the usual "experimenter" code.
899 */
900
901static inline int
902of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
903{
904 if (!OF_VERSION_OKAY(version)) {
905 return -1;
906 }
907 switch (id) {
908""")
909 # Assumes 1.2 contains all stats types and type values are
910 # the same across all versions
911 flow_mod_names = dict()
912 for ver in of_g.of_version_range:
913 for name, value in type_maps.flow_mod_types[ver].items():
914 if name in flow_mod_names and \
915 (not value == flow_mod_names[name]):
916 print "ERROR flow mod command differ violating assumption"
917 sys.exit(1)
918 flow_mod_names[name] = value
919
920 for name, value in flow_mod_names.items():
921 out.write(" case OF_FLOW_%s:\n" % name.upper())
922 for version in of_g.of_version_range:
923 if not name in type_maps.flow_mod_types[version]:
924 out.write(" if (version == %s) break;\n" %
925 of_g.of_version_wire2name[version])
926 out.write(" return %d;\n" % value)
927 out.write("""
928 default:
929 break;
930 }
931 return -1; /* Not recognized as flow mod type object for this version */
932}
933
934""")
935
936def gen_type_maps_header(out):
937 """
938 Generate various header file declarations for type maps
939 @param out The file handle to write to
940 """
941
942 out.write("""
943/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700944 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700945 * top level message: Action, instruction, error, stats, queue_props, oxm
946 */
947#define OF_EXPERIMENTER_TYPE 0xffff
948""")
949 gen_type_to_obj_map_functions(out)
950 gen_obj_to_type_map_functions(out)
951
Rich Laneb157b0f2013-03-27 13:55:28 -0700952 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700953 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700954
955 out.write("""
956/**
957 * Map a message in a wire buffer object to its OF object id.
958 * @param wbuf Pointer to a wire buffer object, populated with an OF message
959 * @returns The object ID of the message
960 * @returns OF_OBJECT_INVALID if unable to parse the message type
961 */
962
963static inline of_object_id_t
964of_wire_object_id_get(of_wire_buffer_t *wbuf)
965{
966 of_message_t msg;
967
968 msg = (of_message_t)WBUF_BUF(wbuf);
969 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
970}
971
972/**
973 * Use the type/length from the wire buffer and init the object
974 * @param obj The object being initialized
975 * @param base_object_id If > 0, this indicates the base object
976 * @param max_len If > 0, the max length to expect for the obj
977 * type for inheritance checking
978 * @return OF_ERROR_
979 *
980 * Used for inheritance type objects such as actions and OXMs
981 * The type is checked and if valid, the object is initialized.
982 * Then the length is taken from the buffer.
983 *
984 * Note that the object version must already be properly set.
985 */
986static inline int
987of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
988 int max_len)
989{
990 if (obj->wire_type_get != NULL) {
991 of_object_id_t id;
992 obj->wire_type_get(obj, &id);
993 if (!of_wire_id_valid(id, base_object_id)) {
994 return OF_ERROR_PARSE;
995 }
996 obj->object_id = id;
997 /* Call the init function for this object type; do not push to wire */
998 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
999 }
1000 if (obj->wire_length_get != NULL) {
1001 int length;
1002 obj->wire_length_get(obj, &length);
1003 if (length < 0 || (max_len > 0 && length > max_len)) {
1004 return OF_ERROR_PARSE;
1005 }
1006 obj->length = length;
1007 } else {
1008 /* @fixme Does this cover everything else? */
1009 obj->length = of_object_fixed_len[obj->version][base_object_id];
1010 }
1011
1012 return OF_ERROR_NONE;
1013}
1014
1015""")
1016
1017 # Generate the function that sets the object type fields
1018 out.write("""
1019
1020/**
1021 * Map a message in a wire buffer object to its OF object id.
1022 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1023 * @returns The object ID of the message
1024 * @returns OF_OBJECT_INVALID if unable to parse the message type
1025 *
1026 * Version must be set in the buffer prior to calling this routine
1027 */
1028
1029static inline int
1030of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
1031{
1032 int type;
1033 of_version_t ver;
1034 of_message_t msg;
1035
1036 msg = (of_message_t)WBUF_BUF(wbuf);
1037
1038 ver = of_message_version_get(msg);
1039
1040 /* ASSERT(id is a message object) */
1041
1042 if ((type = of_object_to_wire_type(id, ver)) < 0) {
1043 return OF_ERROR_PARAM;
1044 }
1045 of_message_type_set(msg, type);
1046
1047 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
1048 /* It's a stats obj */
1049 of_message_stats_type_set(msg, type);
1050 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001051 if ((type = of_object_to_error_type(id, ver)) >= 0) {
Rob Vaterlausb5e8c832013-10-04 12:50:23 -07001052 /* It's an error obj */
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001053 of_message_error_type_set(msg, type);
1054 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001055 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
1056 /* It's a flow mod obj */
1057 of_message_flow_mod_command_set(msg, ver, type);
1058 }
1059 if (of_object_id_is_extension(id, ver)) {
1060 uint32_t val32;
1061
1062 /* Set the experimenter and subtype codes */
1063 val32 = of_extension_to_experimenter_id(id, ver);
1064 of_message_experimenter_id_set(msg, val32);
1065 val32 = of_extension_to_experimenter_subtype(id, ver);
1066 of_message_experimenter_subtype_set(msg, val32);
1067 }
1068
1069 return OF_ERROR_NONE;
1070}
1071""")
1072
1073def gen_type_data_header(out):
1074
1075 out.write("""
1076/****************************************************************
1077 *
1078 * The following declarations are for type and length calculations.
1079 * Implementations may be found in of_type_maps.c
1080 *
1081 ****************************************************************/
1082/*
1083 * Special case length functions for objects with
1084 */
1085""")
1086 for ((cls, name), prev) in of_g.special_offsets.items():
1087 s_cls = cls[3:] # take off of_
1088 out.write("""
1089/**
1090 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001091 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001092 * length of %(name)s
1093 * @param bytes[out] Where to store the calculated length
1094 *
1095 * Preceding data member is %(prev)s.
1096 */
1097extern int of_length_%(s_cls)s_%(name)s_get(
1098 %(cls)s_t *obj, int *bytes);
1099
1100/**
1101 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001102 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001103 * length of %(name)s
1104 * @param offset[out] Where to store the calculated length
1105 *
1106 * Preceding data member is %(prev)s.
1107 */
1108extern int of_offset_%(s_cls)s_%(name)s_get(
1109 %(cls)s_t *obj, int *offset);
1110""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1111
1112# NOT NEEDED YET
1113# # For non-message, variable length objects, give a fun that
1114# # calculates the length
1115# for cls in of_g.standard_class_order:
1116# s_cls = cls[3:] # take off of_
1117# if !type_is_var_len(cls, version):
1118# continue
1119# out.write("""
1120# /**
1121# * Special length calculation for variable length object %(cls)s
1122# * @param obj An object of type %(cls)s whose length is being calculated
1123# * @param bytes[out] Where to store the calculated length
1124# *
1125# * The assumption is that the length member of the object is not
1126# * valid and the length needs to be calculated from other information
1127# * such as the parent.
1128# */
1129# extern int of_length_%(s_cls)s_get(
1130# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001131# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001132
1133 out.write("""
1134/****************************************************************
1135 * Wire type/length functions.
1136 ****************************************************************/
1137
1138extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1139extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1140
1141extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1142extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1143extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1144extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1145
1146extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1147extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1148
1149extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1150
1151/* Wire length is uint16 at front of structure */
1152extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1153extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1154
1155extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1156extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001157extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001158 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001159extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001160 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001161extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001162 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001163extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001164 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001165extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001166 of_object_id_t *id);
1167
Rich Lane47085722013-07-12 16:27:04 -07001168#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001169#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001170 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001171
1172extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1173extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1174
1175extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1176 int *bytes);
1177extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1178extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1179extern int of_extension_object_wire_push(of_object_t *obj);
1180
1181""")
1182
1183
1184def gen_length_array(out):
1185 """
1186 Generate an array giving the lengths of all objects/versions
1187 @param out The file handle to which to write
1188 """
1189 out.write("""
1190/**
1191 * An array with the number of bytes in the fixed length part
1192 * of each OF object
1193 */
1194""")
1195
1196 for version in of_g.of_version_range:
1197 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001198static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001199 -1, /* of_object is not instantiable */
1200""" % version)
1201 for i, cls in enumerate(of_g.all_class_order):
1202 comma = ","
1203 if i == len(of_g.all_class_order) - 1:
1204 comma = ""
1205 val = "-1" + comma
1206 if (cls, version) in of_g.base_length:
1207 val = str(of_g.base_length[(cls, version)]) + comma
1208 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1209 out.write("};\n")
1210
1211 out.write("""
1212/**
1213 * Unified map of fixed length part of each object
1214 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001215const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001216 NULL,
1217""")
1218 for version in of_g.of_version_range:
1219 out.write(" of_object_fixed_len_v%d,\n" % version)
1220 out.write("""
1221};
1222""")
1223
Andreas Wundsam53256162013-05-02 14:05:53 -07001224
Rich Lanef70be942013-07-18 13:33:14 -07001225def gen_extra_length_array(out):
1226 """
1227 Generate an array giving the extra lengths of all objects/versions
1228 @param out The file handle to which to write
1229 """
1230 out.write("""
1231/**
1232 * An array with the number of bytes in the extra length part
1233 * of each OF object
1234 */
1235""")
1236
1237 for version in of_g.of_version_range:
1238 out.write("""
1239static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1240 -1, /* of_object is not instantiable */
1241""" % version)
1242 for i, cls in enumerate(of_g.all_class_order):
1243 comma = ","
1244 if i == len(of_g.all_class_order) - 1:
1245 comma = ""
1246 val = "-1" + comma
1247 if (cls, version) in of_g.base_length:
1248 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1249 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1250 out.write("};\n")
1251
1252 out.write("""
1253/**
1254 * Unified map of extra length part of each object
1255 */
1256const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1257 NULL,
1258""")
1259 for version in of_g.of_version_range:
1260 out.write(" of_object_extra_len_v%d,\n" % version)
1261 out.write("""
1262};
1263""")
1264
1265
Rich Lanea06d0c32013-03-25 08:52:03 -07001266################################################################
1267################################################################
1268
1269# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1270def gen_object_id_to_stats_type(out):
1271 out.write("""
1272/**
1273 * Map from message object ID to stats type
1274 *
1275 * All message object IDs are mapped for simplicity
1276 */
1277""")
1278 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001279 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001280 out.write(" -1, /* of_object (invalid) */\n");
1281 for cls in of_g.ordered_messages:
1282 name = cls[3:]
1283 name = name[:name.find("_stats")]
1284 if (((cls in type_maps.stats_reply_list) or
1285 (cls in type_maps.stats_request_list)) and
1286 name in type_maps.stats_types[i]):
1287 out.write(" %d, /* %s */\n" %
1288 (type_maps.stats_types[i][name], cls))
1289 else:
1290 out.write(" -1, /* %s (invalid) */\n" % cls)
1291 out.write("};\n\n")
1292
1293 out.write("""
1294/**
1295 * Unified map, indexed by wire version which is 1-based.
1296 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001297const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001298 NULL,
1299""")
1300 for version in of_g.of_version_range:
1301 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1302 out.write("""
1303};
1304""")
1305