blob: 43cd4a8f85472150866c5375e211fc82060285c1 [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
Andreas Wundsam76db0062013-11-15 13:34:41 -080032import c_gen.of_g_legacy as of_g
Rich Lanea06d0c32013-03-25 08:52:03 -070033import 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;
Rich Lane353a79f2013-11-13 10:39:56 -0800506 uint32_t experimenter, subtype;
Rich Lanea06d0c32013-03-25 08:52:03 -0700507
508 if (length < OF_MESSAGE_MIN_LENGTH) {
509 return OF_OBJECT_INVALID;
510 }
511 type = of_message_type_get(msg);
512 ver = of_message_version_get(msg);
513 if (!OF_VERSION_OKAY(ver)) {
514 return OF_OBJECT_INVALID;
515 }
516
517 if (type >= OF_MESSAGE_ITEM_COUNT) {
518 return OF_OBJECT_INVALID;
519 }
520
521 obj_id = of_message_type_to_id[ver][type];
522
523 /* Remap to specific message if known */
524 if (obj_id == OF_EXPERIMENTER) {
525 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
526 return OF_OBJECT_INVALID;
527 }
528 return of_message_experimenter_to_object_id(msg, ver);
529 }
530
531 /* Remap to add/delete/strict version */
532 if (obj_id == OF_FLOW_MOD) {
533 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
534 return OF_OBJECT_INVALID;
535 }
536 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
537 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
538 }
539
540 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
541 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
542 return OF_OBJECT_INVALID;
543 }
544 stats_type = of_message_stats_type_get(msg);
Rich Lane353a79f2013-11-13 10:39:56 -0800545 if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
546 if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
547 return OF_OBJECT_INVALID;
548 }
549 experimenter = of_message_stats_experimenter_id_get(msg);
550 subtype = of_message_stats_experimenter_subtype_get(msg);
551 if (obj_id == OF_STATS_REQUEST) {
552 obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
553 } else {
554 obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
555 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700556 } else {
Rich Lane353a79f2013-11-13 10:39:56 -0800557 if (obj_id == OF_STATS_REQUEST) {
558 obj_id = of_stats_request_to_object_id(stats_type, ver);
559 } else {
560 obj_id = of_stats_reply_to_object_id(stats_type, ver);
561 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 }
563 }
564
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700565 if (obj_id == OF_ERROR_MSG) {
566 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
567 return OF_OBJECT_INVALID;
568 }
569 err_type = of_message_error_type_get(msg);
570 obj_id = of_error_msg_to_object_id(err_type, ver);
571 }
572
Rich Lanea06d0c32013-03-25 08:52:03 -0700573 return obj_id;
574}
575"""
576
Rich Laned8d29c92013-09-24 13:46:42 -0700577 oxm_template = """
578/**
579 * oxm wire type to object ID array.
580 * Treat as private; use function accessor below
581 */
582
583extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
584
585#define OF_OXM_ITEM_COUNT %(ar_len)d\n
586
587/**
588 * Map an oxm wire value to an OF object
589 * @param oxm The oxm type wire value
590 * @param version The version associated with the check
591 * @return The oxm OF object type
592 * @return OF_OBJECT_INVALID if type does not map to an object
593 *
594 */
595static inline of_object_id_t
596of_oxm_to_object_id(uint32_t type_len, of_version_t version)
597{
598 if (!OF_VERSION_OKAY(version)) {
599 return OF_OBJECT_INVALID;
600 }
601
602 uint16_t class = (type_len >> 16) & 0xffff;
603 uint8_t masked_type = (type_len >> 8) & 0xff;
604
605 if (class == 0x8000) {
606 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
607 return OF_OBJECT_INVALID;
608 }
609
610 return of_oxm_type_to_id[version][masked_type];
611 } else if (class == 0x0003) {
612 switch (masked_type) {
613 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
614 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
Rich Lane61718362013-10-24 16:59:42 -0700615 case 0x02: return OF_OXM_BSN_LAG_ID;
616 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laneeb21c4f2013-10-28 17:34:41 -0700617 case 0x04: return OF_OXM_BSN_VRF;
618 case 0x05: return OF_OXM_BSN_VRF_MASKED;
619 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
620 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
621 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
622 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
623 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
624 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
625 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
626 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700627 default: return OF_OBJECT_INVALID;
628 }
629 } else {
630 return OF_OBJECT_INVALID;
631 }
632}
633"""
634
Rich Lanea06d0c32013-03-25 08:52:03 -0700635 # Action types array gen
636 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700637 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700638 dict(name="action", u_name="ACTION", ar_len=ar_len))
639
640 # Action ID types array gen
641 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700642 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700643 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
644
645 # Instruction types array gen
646 ar_len = type_maps.type_array_len(type_maps.instruction_types,
647 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700648 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700649 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
650
651 # Queue prop types array gen
652 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
653 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700654 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700655 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
656
657 # Table feature prop types array gen
658 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
659 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700660 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700661 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
662 ar_len=ar_len))
663
664 # Meter band types array gen
665 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
666 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700667 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700668 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
669
670 # Hello elem types array gen
671 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
672 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700673 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700674 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
675
676 # Stats types array gen
677 ar_len = type_maps.type_array_len(type_maps.stats_types,
678 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700679 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700680 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700681 out.write(stats_template %
682 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700683 ar_len=ar_len))
684
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700685 ar_len = type_maps.type_array_len(type_maps.error_types,
686 max_type_value)
687 out.write(error_msg_template %
688 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
689# out.write(error_msg_function)
690
Rich Lanea06d0c32013-03-25 08:52:03 -0700691 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700692 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700693 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
694
Rich Laned8d29c92013-09-24 13:46:42 -0700695 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700696 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
697 out.write("""
698/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
699""")
Rich Laned8d29c92013-09-24 13:46:42 -0700700 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700701
Rich Laned8d29c92013-09-24 13:46:42 -0700702 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700703 out.write(experimenter_function)
704 # Must follow stats reply/request
705 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700706 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700707 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
708
709def gen_obj_to_type_map_functions(out):
710 """
711 Generate the static line maps from object IDs to types
712 @param out The file handle to write to
713 """
714
715 ################################################################
716 # Generate object ID to primary type map
717 ################################################################
718
719 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700720extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700721
722/**
723 * Map an object ID to its primary wire type value
724 * @param id An object ID
725 * @return For message objects, the type value in the OpenFlow header
726 * @return For non-message objects such as actions, instructions, OXMs
727 * returns the type value that appears in the respective sub-header
728 * @return -1 For improper version or out of bounds input
729 *
730 * NOTE that for stats request/reply, returns the header type, not the
731 * sub-type
732 *
733 * Also, note that the value is returned as a signed integer. So -1 is
734 * an error code, while 0xffff is the usual "experimenter" code.
735 */
736static inline int
737of_object_to_wire_type(of_object_id_t id, of_version_t version)
738{
739 if (!OF_VERSION_OKAY(version)) {
740 return -1;
741 }
742 if (id < 0 || id >= OF_OBJECT_COUNT) {
743 return -1;
744 }
745 return of_object_to_type_map[version][id];
746}
747
748""")
749
750 # Now for experimenter ids
751 out.write("""
752/**
753 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
754 */
755""")
756 out.write("""
757typedef struct of_experimenter_data_s {
758 int is_extension; /* Boolean indication that this is an extension */
759 uint32_t experimenter_id;
760 uint32_t subtype;
761} of_experimenter_data_t;
762
763""")
764
765 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700766extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700767
768/**
769 * Map from the object ID of an extension to the experimenter ID
770 */
771static inline uint32_t
772of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
773{
774 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
775 return (uint32_t) -1;
776 }
777 /* @fixme: Verify ver? */
778 return of_object_to_extension_data[ver][obj_id].experimenter_id;
779}
780
781/**
782 * Map from the object ID of an extension to the experimenter subtype
783 */
784static inline uint32_t
785of_extension_to_experimenter_subtype(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].subtype;
792}
793
794/**
795 * Boolean function indicating the the given object ID/version
796 * is recognized as a supported (decode-able) extension.
797 */
798static inline int
799of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
800{
801 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
802 return (uint32_t) -1;
803 }
804 /* @fixme: Verify ver? */
805 return of_object_to_extension_data[ver][obj_id].is_extension;
806}
807""")
808
809 ################################################################
810 # Generate object ID to the stats sub-type map
811 ################################################################
812
813 out.write("""
814/**
815 * Map an object ID to a stats type
816 * @param id An object ID
817 * @return The wire value for the stats type
818 * @return -1 if not supported for this version
819 * @return -1 if id is not a specific stats type ID
820 *
821 * Note that the value is returned as a signed integer. So -1 is
822 * an error code, while 0xffff is the usual "experimenter" code.
823 */
824
825static inline int
826of_object_to_stats_type(of_object_id_t id, of_version_t version)
827{
828 if (!OF_VERSION_OKAY(version)) {
829 return -1;
830 }
831 switch (id) {
832""")
833 # Assumes 1.2 contains all stats types and type values are
834 # the same across all versions
835 stats_names = dict()
836 for ver in of_g.of_version_range:
837 for name, value in type_maps.stats_types[ver].items():
838 if name in stats_names and (not value == stats_names[name]):
839 print "ERROR stats type differ violating assumption"
840 sys.exit(1)
841 stats_names[name] = value
842
843 for name, value in stats_names.items():
844 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
845 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
846 for version in of_g.of_version_range:
847 if not name in type_maps.stats_types[version]:
848 out.write(" if (version == %s) break;\n" %
849 of_g.of_version_wire2name[version])
850 out.write(" return %d;\n" % value)
851 out.write("""
852 default:
853 break;
854 }
855 return -1; /* Not recognized as stats type object for this version */
856}
857""")
858
859 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700860 # Generate object ID to the error sub-type map
861 ################################################################
862 out.write("""
863/**
864 * Map an object ID to an error type
865 * @param id An object ID
866 * @return The wire value for the error type
867 * @return -1 if not supported for this version
868 * @return -1 if id is not a specific error type ID
869 *
870 * Note that the value is returned as a signed integer. So -1 is
871 * an error code, while 0xffff is the usual "experimenter" code.
872 */
873
874static inline int
875of_object_to_error_type(of_object_id_t id, of_version_t version)
876{
877 if (!OF_VERSION_OKAY(version)) {
878 return -1;
879 }
880 switch (id) {""")
881 error_names = set()
882 for ver in of_g.of_version_range:
883 for name in type_maps.error_types[ver]:
884 error_names.add(name)
885 for name in error_names:
886 out.write("""
887 case OF_%(name)s_ERROR_MSG:
888 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
889 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
890 break;""" % {"name": name.upper()})
891 out.write("""
892 default:
893 break;
894 }
895 return -1; /* Not recognized as error type object for this version */
896}
897""")
898
899 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700900 # Generate object ID to the flow mod sub-type map
901 ################################################################
902
903 out.write("""
904/**
905 * Map an object ID to a flow-mod command value
906 * @param id An object ID
907 * @return The wire value for the flow-mod command
908 * @return -1 if not supported for this version
909 * @return -1 if id is not a specific stats type ID
910 *
911 * Note that the value is returned as a signed integer. So -1 is
912 * an error code, while 0xffff is the usual "experimenter" code.
913 */
914
915static inline int
916of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
917{
918 if (!OF_VERSION_OKAY(version)) {
919 return -1;
920 }
921 switch (id) {
922""")
923 # Assumes 1.2 contains all stats types and type values are
924 # the same across all versions
925 flow_mod_names = dict()
926 for ver in of_g.of_version_range:
927 for name, value in type_maps.flow_mod_types[ver].items():
928 if name in flow_mod_names and \
929 (not value == flow_mod_names[name]):
930 print "ERROR flow mod command differ violating assumption"
931 sys.exit(1)
932 flow_mod_names[name] = value
933
934 for name, value in flow_mod_names.items():
935 out.write(" case OF_FLOW_%s:\n" % name.upper())
936 for version in of_g.of_version_range:
937 if not name in type_maps.flow_mod_types[version]:
938 out.write(" if (version == %s) break;\n" %
939 of_g.of_version_wire2name[version])
940 out.write(" return %d;\n" % value)
941 out.write("""
942 default:
943 break;
944 }
945 return -1; /* Not recognized as flow mod type object for this version */
946}
947
948""")
949
950def gen_type_maps_header(out):
951 """
952 Generate various header file declarations for type maps
953 @param out The file handle to write to
954 """
955
956 out.write("""
957/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700958 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700959 * top level message: Action, instruction, error, stats, queue_props, oxm
960 */
961#define OF_EXPERIMENTER_TYPE 0xffff
Rich Lane353a79f2013-11-13 10:39:56 -0800962
963int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
964int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
Rich Lanea06d0c32013-03-25 08:52:03 -0700965""")
966 gen_type_to_obj_map_functions(out)
967 gen_obj_to_type_map_functions(out)
968
Rich Laneb157b0f2013-03-27 13:55:28 -0700969 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700970 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700971
972 out.write("""
973/**
974 * Map a message in a wire buffer object to its OF object id.
975 * @param wbuf Pointer to a wire buffer object, populated with an OF message
976 * @returns The object ID of the message
977 * @returns OF_OBJECT_INVALID if unable to parse the message type
978 */
979
980static inline of_object_id_t
981of_wire_object_id_get(of_wire_buffer_t *wbuf)
982{
983 of_message_t msg;
984
985 msg = (of_message_t)WBUF_BUF(wbuf);
986 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
987}
988
989/**
990 * Use the type/length from the wire buffer and init the object
991 * @param obj The object being initialized
992 * @param base_object_id If > 0, this indicates the base object
993 * @param max_len If > 0, the max length to expect for the obj
994 * type for inheritance checking
995 * @return OF_ERROR_
996 *
997 * Used for inheritance type objects such as actions and OXMs
998 * The type is checked and if valid, the object is initialized.
999 * Then the length is taken from the buffer.
1000 *
1001 * Note that the object version must already be properly set.
1002 */
1003static inline int
1004of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
1005 int max_len)
1006{
1007 if (obj->wire_type_get != NULL) {
1008 of_object_id_t id;
1009 obj->wire_type_get(obj, &id);
1010 if (!of_wire_id_valid(id, base_object_id)) {
1011 return OF_ERROR_PARSE;
1012 }
1013 obj->object_id = id;
1014 /* Call the init function for this object type; do not push to wire */
1015 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
1016 }
1017 if (obj->wire_length_get != NULL) {
1018 int length;
1019 obj->wire_length_get(obj, &length);
1020 if (length < 0 || (max_len > 0 && length > max_len)) {
1021 return OF_ERROR_PARSE;
1022 }
1023 obj->length = length;
1024 } else {
1025 /* @fixme Does this cover everything else? */
1026 obj->length = of_object_fixed_len[obj->version][base_object_id];
1027 }
1028
1029 return OF_ERROR_NONE;
1030}
1031
1032""")
1033
1034 # Generate the function that sets the object type fields
1035 out.write("""
1036
1037/**
1038 * Map a message in a wire buffer object to its OF object id.
1039 * @param wbuf Pointer to a wire buffer object, populated with an OF message
1040 * @returns The object ID of the message
1041 * @returns OF_OBJECT_INVALID if unable to parse the message type
1042 *
1043 * Version must be set in the buffer prior to calling this routine
1044 */
1045
1046static inline int
1047of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
1048{
1049 int type;
1050 of_version_t ver;
1051 of_message_t msg;
1052
1053 msg = (of_message_t)WBUF_BUF(wbuf);
1054
1055 ver = of_message_version_get(msg);
1056
1057 /* ASSERT(id is a message object) */
1058
1059 if ((type = of_object_to_wire_type(id, ver)) < 0) {
1060 return OF_ERROR_PARAM;
1061 }
1062 of_message_type_set(msg, type);
1063
1064 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
1065 /* It's a stats obj */
1066 of_message_stats_type_set(msg, type);
Rich Lane353a79f2013-11-13 10:39:56 -08001067 if (type == OF_STATS_TYPE_EXPERIMENTER) {
1068 switch (id) {
1069 case OF_BSN_LACP_STATS_REQUEST:
1070 case OF_BSN_LACP_STATS_REPLY:
1071 of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
1072 of_message_stats_experimenter_subtype_set(msg, 1);
1073 break;
Wilson Ng45386fb2013-12-03 13:46:42 -08001074 case OF_BSN_SWITCH_PIPELINE_STATS_REQUEST:
1075 case OF_BSN_SWITCH_PIPELINE_STATS_REPLY:
1076 of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
1077 of_message_stats_experimenter_subtype_set(msg, 6);
1078 break;
Rich Lane353a79f2013-11-13 10:39:56 -08001079 default:
1080 break;
1081 }
1082 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001083 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001084 if ((type = of_object_to_error_type(id, ver)) >= 0) {
Rob Vaterlausb5e8c832013-10-04 12:50:23 -07001085 /* It's an error obj */
Rob Vaterlausb3f49d92013-10-01 17:57:31 -07001086 of_message_error_type_set(msg, type);
1087 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001088 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
1089 /* It's a flow mod obj */
1090 of_message_flow_mod_command_set(msg, ver, type);
1091 }
1092 if (of_object_id_is_extension(id, ver)) {
1093 uint32_t val32;
1094
1095 /* Set the experimenter and subtype codes */
1096 val32 = of_extension_to_experimenter_id(id, ver);
1097 of_message_experimenter_id_set(msg, val32);
1098 val32 = of_extension_to_experimenter_subtype(id, ver);
1099 of_message_experimenter_subtype_set(msg, val32);
1100 }
1101
1102 return OF_ERROR_NONE;
1103}
1104""")
1105
1106def gen_type_data_header(out):
1107
1108 out.write("""
1109/****************************************************************
1110 *
1111 * The following declarations are for type and length calculations.
1112 * Implementations may be found in of_type_maps.c
1113 *
1114 ****************************************************************/
1115/*
1116 * Special case length functions for objects with
1117 */
1118""")
1119 for ((cls, name), prev) in of_g.special_offsets.items():
1120 s_cls = cls[3:] # take off of_
1121 out.write("""
1122/**
1123 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001124 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001125 * length of %(name)s
1126 * @param bytes[out] Where to store the calculated length
1127 *
1128 * Preceding data member is %(prev)s.
1129 */
1130extern int of_length_%(s_cls)s_%(name)s_get(
1131 %(cls)s_t *obj, int *bytes);
1132
1133/**
1134 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001135 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001136 * length of %(name)s
1137 * @param offset[out] Where to store the calculated length
1138 *
1139 * Preceding data member is %(prev)s.
1140 */
1141extern int of_offset_%(s_cls)s_%(name)s_get(
1142 %(cls)s_t *obj, int *offset);
1143""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1144
1145# NOT NEEDED YET
1146# # For non-message, variable length objects, give a fun that
1147# # calculates the length
1148# for cls in of_g.standard_class_order:
1149# s_cls = cls[3:] # take off of_
1150# if !type_is_var_len(cls, version):
1151# continue
1152# out.write("""
1153# /**
1154# * Special length calculation for variable length object %(cls)s
1155# * @param obj An object of type %(cls)s whose length is being calculated
1156# * @param bytes[out] Where to store the calculated length
1157# *
1158# * The assumption is that the length member of the object is not
1159# * valid and the length needs to be calculated from other information
1160# * such as the parent.
1161# */
1162# extern int of_length_%(s_cls)s_get(
1163# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001164# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001165
1166 out.write("""
1167/****************************************************************
1168 * Wire type/length functions.
1169 ****************************************************************/
1170
1171extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1172extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1173
1174extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1175extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1176extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1177extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1178
1179extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1180extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1181
1182extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1183
1184/* Wire length is uint16 at front of structure */
1185extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1186extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1187
1188extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1189extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001190extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001191 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001192extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001193 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001194extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001195 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001196extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001197 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001198extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001199 of_object_id_t *id);
1200
Rich Lane47085722013-07-12 16:27:04 -07001201#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001202#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001203 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001204
1205extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1206extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1207
1208extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1209 int *bytes);
1210extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1211extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1212extern int of_extension_object_wire_push(of_object_t *obj);
1213
1214""")
1215
1216
1217def gen_length_array(out):
1218 """
1219 Generate an array giving the lengths of all objects/versions
1220 @param out The file handle to which to write
1221 """
1222 out.write("""
1223/**
1224 * An array with the number of bytes in the fixed length part
1225 * of each OF object
1226 */
1227""")
1228
1229 for version in of_g.of_version_range:
1230 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001231static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001232 -1, /* of_object is not instantiable */
1233""" % version)
1234 for i, cls in enumerate(of_g.all_class_order):
1235 comma = ","
1236 if i == len(of_g.all_class_order) - 1:
1237 comma = ""
1238 val = "-1" + comma
1239 if (cls, version) in of_g.base_length:
1240 val = str(of_g.base_length[(cls, version)]) + comma
1241 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1242 out.write("};\n")
1243
1244 out.write("""
1245/**
1246 * Unified map of fixed length part of each object
1247 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001248const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001249 NULL,
1250""")
1251 for version in of_g.of_version_range:
1252 out.write(" of_object_fixed_len_v%d,\n" % version)
1253 out.write("""
1254};
1255""")
1256
Andreas Wundsam53256162013-05-02 14:05:53 -07001257
Rich Lanef70be942013-07-18 13:33:14 -07001258def gen_extra_length_array(out):
1259 """
1260 Generate an array giving the extra lengths of all objects/versions
1261 @param out The file handle to which to write
1262 """
1263 out.write("""
1264/**
1265 * An array with the number of bytes in the extra length part
1266 * of each OF object
1267 */
1268""")
1269
1270 for version in of_g.of_version_range:
1271 out.write("""
1272static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1273 -1, /* of_object is not instantiable */
1274""" % version)
1275 for i, cls in enumerate(of_g.all_class_order):
1276 comma = ","
1277 if i == len(of_g.all_class_order) - 1:
1278 comma = ""
1279 val = "-1" + comma
1280 if (cls, version) in of_g.base_length:
1281 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1282 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1283 out.write("};\n")
1284
1285 out.write("""
1286/**
1287 * Unified map of extra length part of each object
1288 */
1289const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1290 NULL,
1291""")
1292 for version in of_g.of_version_range:
1293 out.write(" of_object_extra_len_v%d,\n" % version)
1294 out.write("""
1295};
1296""")
1297
1298
Rich Lanea06d0c32013-03-25 08:52:03 -07001299################################################################
1300################################################################
1301
1302# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1303def gen_object_id_to_stats_type(out):
1304 out.write("""
1305/**
1306 * Map from message object ID to stats type
1307 *
1308 * All message object IDs are mapped for simplicity
1309 */
1310""")
1311 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001312 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001313 out.write(" -1, /* of_object (invalid) */\n");
1314 for cls in of_g.ordered_messages:
1315 name = cls[3:]
1316 name = name[:name.find("_stats")]
1317 if (((cls in type_maps.stats_reply_list) or
1318 (cls in type_maps.stats_request_list)) and
1319 name in type_maps.stats_types[i]):
1320 out.write(" %d, /* %s */\n" %
1321 (type_maps.stats_types[i][name], cls))
1322 else:
1323 out.write(" -1, /* %s (invalid) */\n" % cls)
1324 out.write("};\n\n")
1325
1326 out.write("""
1327/**
1328 * Unified map, indexed by wire version which is 1-based.
1329 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001330const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001331 NULL,
1332""")
1333 for version in of_g.of_version_range:
1334 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1335 out.write("""
1336};
1337""")
1338