blob: c5d69d0dbb949d21be02db55830643ee2b825967 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28##
29# @brief C code generation for LOXI type related maps
30#
31
32import of_g
33import sys
34from generic_utils import *
Rich Lanea06d0c32013-03-25 08:52:03 -070035import loxi_front_end.type_maps as type_maps
36
37
38# Some number larger than small type values, but less then
39# reserved values like 0xffff
40max_type_value = 1000
41
42def gen_object_id_to_type(out):
43 out.write("""
44/**
45 * Map from object ID to primary wire type
46 *
47 * For messages, this is the header type; in particular for stats, this is
48 * the common stats request/response type. For per-stats types, use the
49 * stats type map. For things like actions, instructions or queue-props,
50 * this gives the "sub type".
51 */
52""")
53 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -070054 out.write("static const int\nof_object_to_type_map_v%d[OF_OBJECT_COUNT] = {\n"
Rich Lanea06d0c32013-03-25 08:52:03 -070055 %version)
56 out.write(" -1, /* of_object, not a valid specific type */\n")
57 for j, cls in enumerate(of_g.all_class_order):
58 comma = ""
59 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
60 comma = ","
61
62 if cls in type_maps.stats_reply_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070063 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070064 (type_maps.type_val[("of_stats_reply", version)],
65 comma, cls))
66 elif cls in type_maps.stats_request_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070067 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070068 (type_maps.type_val[("of_stats_request", version)],
69 comma, cls))
Rob Vaterlausb3f49d92013-10-01 17:57:31 -070070 elif cls in type_maps.error_msg_list:
71 out.write(" %d%s /* %s */\n" %
72 (type_maps.type_val[("of_error_msg", version)],
73 comma, cls))
Rich Lanea06d0c32013-03-25 08:52:03 -070074 elif cls in type_maps.flow_mod_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070075 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070076 (type_maps.type_val[("of_flow_mod", version)],
77 comma, cls))
78 elif (cls, version) in type_maps.type_val:
Andreas Wundsam53256162013-05-02 14:05:53 -070079 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070080 (type_maps.type_val[(cls, version)], comma, cls))
81 elif type_maps.message_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070082 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070083 (type_maps.type_val[("of_experimenter", version)],
84 comma, cls))
85 elif type_maps.action_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070086 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070087 (type_maps.type_val[("of_action_experimenter",
88 version)],
89 comma, cls))
90 elif type_maps.action_id_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070091 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070092 (type_maps.type_val[("of_action_id_experimenter",
93 version)],
94 comma, cls))
95 elif type_maps.instruction_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070096 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070097 (type_maps.type_val[("of_instruction_experimenter",
98 version)],
99 comma, cls))
100 elif type_maps.queue_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700101 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700102 (type_maps.type_val[("of_queue_prop_experimenter",
103 version)],
104 comma, cls))
105 elif type_maps.table_feature_prop_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -0700106 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700107 (type_maps.type_val[("of_table_feature_prop_experimenter",
108 version)],
109 comma, cls))
110 else:
111 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
112 out.write("};\n\n")
113
114 out.write("""
115/**
116 * Unified map, indexed by wire version which is 1-based.
117 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700118const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700119 NULL,
120""")
121 for version in of_g.of_version_range:
122 out.write(" of_object_to_type_map_v%d,\n" % version)
123 out.write("""
124};
125""")
126
127def gen_object_id_to_extension_data(out):
128 out.write("""
129/**
130 * Extension data.
131 * @fixme There must be a better way to represent this data
132 */
133""")
134 for version in of_g.of_version_range:
135 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700136static const of_experimenter_data_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700137of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
138""" % version)
139 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
140 for j, cls in enumerate(of_g.all_class_order):
141 comma = ""
142 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
143 comma = ","
144
145 if type_maps.class_is_extension(cls, version):
146 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
147 subtype = type_maps.extension_to_subtype(cls, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700148 out.write(" {1, %s, %d}%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 (exp_name, subtype, comma, cls))
150 else:
151 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
152 (comma, cls))
153 out.write("};\n\n")
154
155 out.write("""
156/**
157 * Unified map, indexed by wire version which is 1-based.
158 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700159const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700160 NULL,
161""")
162 for version in of_g.of_version_range:
163 out.write(" of_object_to_extension_data_v%d,\n" % version)
164 out.write("""
165};
166""")
167
168def gen_type_to_object_id(out, type_str, prefix, template,
169 value_array, max_val):
170 """
171 Generate C maps from various message class groups to object ids
172
173 For each version, create an array mapping the type info to the
174 object ID. Then define an array containing those pointers.
175 """
176
177 # Create unified arrays and get length
178 arr_len = type_maps.type_array_len(value_array, max_val)
179 all_ars = []
180 for version, val_dict in value_array.items(): # Per version dict
181 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
182 all_ars.append(ar)
183
184 len_name = "%s_ITEM_COUNT" % prefix
185
186 for i, ar in enumerate(all_ars):
187 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -0700188 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700189 (type_str, version, len_name))
190 for i in range(arr_len):
191 comma = ""
192 if i < arr_len - 1: # Avoid ultimate comma
193 comma = ","
194
195 # Per-version length check
196 if i < len(ar):
197 v = ar[i]
198 else:
199 v = type_maps.invalid_type
200
201 if v == type_maps.invalid_type:
202 out.write(" %-30s /* %d (Invalid) */\n" %
203 ("OF_OBJECT_INVALID" + comma, i))
204 else:
205 name = (template % v.upper()) + comma
206 out.write(" %-30s /* %d */\n" % (name, i))
207 out.write("};\n")
208
209 out.write("""
210/**
211 * Maps from %(c_name)s wire type values to LOCI object ids
212 *
213 * Indexed by wire version which is 1-based.
214 */
215
Rich Laneb157b0f2013-03-27 13:55:28 -0700216const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700217 NULL,
218""" % dict(name=type_str, c_name=prefix.lower()))
219 for version in of_g.of_version_range:
220 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
221 version=version))
222 out.write("""
223};
224
Andreas Wundsam53256162013-05-02 14:05:53 -0700225""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700226 max_val=max_val, c_name=prefix.lower()))
227
228def gen_type_maps(out):
229 """
230 Generate various type maps
231 @param out The file handle to write to
232 """
233
234 out.write("#include <loci/loci.h>\n\n")
235
236 # Generate maps from wire type values to object IDs
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700237 gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
238 "OF_%s_ERROR_MSG", type_maps.error_types,
239 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700240 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
241 "OF_ACTION_%s", type_maps.action_types,
242 max_type_value)
243 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
244 "OF_ACTION_ID_%s", type_maps.action_id_types,
245 max_type_value)
246 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700247 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700248 max_type_value)
249 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
250 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
251 max_type_value)
252 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
253 "OF_TABLE_FEATURE_PROP",
254 "OF_TABLE_FEATURE_PROP_%s",
255 type_maps.table_feature_prop_types,
256 max_type_value)
257 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
258 "OF_METER_BAND_%s", type_maps.meter_band_types,
259 max_type_value)
260 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
261 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
262 max_type_value)
263
264 # FIXME: Multipart re-organization
265 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
266 "OF_%s_STATS_REQUEST", type_maps.stats_types,
267 max_type_value)
268 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
269 "OF_%s_STATS_REPLY", type_maps.stats_types,
270 max_type_value)
271 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
272 "OF_FLOW_%s", type_maps.flow_mod_types,
273 max_type_value)
274 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
275 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
276 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
277 "OF_%s", type_maps.message_types, max_type_value)
278
279 gen_object_id_to_type(out)
280 gen_object_id_to_extension_data(out)
281 # Don't need array mapping ID to stats types right now; handled directly
282 # gen_object_id_to_stats_type(out)
283
284
285def gen_type_to_obj_map_functions(out):
286 """
287 Generate the templated static inline type map functions
288 @param out The file handle to write to
289 """
290
291 ################################################################
292 # Generate all type-to-object-ID maps in a common way
293 ################################################################
294 map_template = """
295/**
296 * %(name)s wire type to object ID array.
297 * Treat as private; use function accessor below
298 */
299
Rich Laneb157b0f2013-03-27 13:55:28 -0700300extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700301
302#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
303
304/**
305 * Map an %(name)s wire value to an OF object
306 * @param %(name)s The %(name)s type wire value
307 * @param version The version associated with the check
308 * @return The %(name)s OF object type
309 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700310 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700311 */
312static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700313of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700314{
315 if (!OF_VERSION_OKAY(version)) {
316 return OF_OBJECT_INVALID;
317 }
318 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
319 return OF_OBJECT_INVALID;
320 }
321
322 return of_%(name)s_type_to_id[version][%(name)s];
323}
324"""
325 map_with_experimenter_template = """
326/**
327 * %(name)s wire type to object ID array.
328 * Treat as private; use function accessor below
329 */
330
Rich Laneb157b0f2013-03-27 13:55:28 -0700331extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700332
333#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
334
335/**
336 * Map an %(name)s wire value to an OF object
337 * @param %(name)s The %(name)s type wire value
338 * @param version The version associated with the check
339 * @return The %(name)s OF object type
340 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700341 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700342 */
343static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700344of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700345{
346 if (!OF_VERSION_OKAY(version)) {
347 return OF_OBJECT_INVALID;
348 }
349 if (%(name)s == OF_EXPERIMENTER_TYPE) {
350 return OF_%(u_name)s_EXPERIMENTER;
351 }
352 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
353 return OF_OBJECT_INVALID;
354 }
355
356 return of_%(name)s_type_to_id[version][%(name)s];
357}
358"""
359
360 stats_template = """
361/**
362 * %(name)s wire type to object ID array.
363 * Treat as private; use function accessor below
364 */
365
Rich Laneb157b0f2013-03-27 13:55:28 -0700366extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700367
368#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
369
370/**
371 * Map an %(name)s wire value to an OF object
372 * @param %(name)s The %(name)s type wire value
373 * @param version The version associated with the check
374 * @return The %(name)s OF object type
375 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700376 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700377 */
378static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700379of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700380{
381 if (!OF_VERSION_OKAY(version)) {
382 return OF_OBJECT_INVALID;
383 }
384 if (%(name)s == OF_EXPERIMENTER_TYPE) {
385 return OF_EXPERIMENTER_%(u_name)s;
386 }
387 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
388 return OF_OBJECT_INVALID;
389 }
390
391 return of_%(name)s_type_to_id[version][%(name)s];
392}
393"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700394
395 error_msg_template = """
396/**
397 * %(name)s wire type to object ID array.
398 * Treat as private; use function accessor below
399 */
400
401extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
402
403#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
404
405/**
406 * Map an %(name)s wire value to an OF object
407 * @param %(name)s The %(name)s type wire value
408 * @param version The version associated with the check
409 * @return The %(name)s OF object type
410 * @return OF_OBJECT_INVALID if type does not map to an object
411 *
412 */
413static inline of_object_id_t
414of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
415{
416 if (!OF_VERSION_OKAY(version)) {
417 return OF_OBJECT_INVALID;
418 }
419 if (%(name)s == OF_EXPERIMENTER_TYPE) {
420 return OF_EXPERIMENTER_ERROR_MSG;
421 }
422 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
423 return OF_OBJECT_INVALID;
424 }
425
426 return of_%(name)s_type_to_id[version][%(name)s];
427}
428"""
429
Rich Lanea06d0c32013-03-25 08:52:03 -0700430 # Experimenter mapping functions
431 # Currently we support very few candidates, so we just do a
432 # list of if/elses
433 experimenter_function = """
434/**
435 * @brief Map a message known to be an exp msg to the proper object
436 *
437 * Assume that the message is a vendor/experimenter message. Determine
438 * the specific object type for the message.
439 * @param msg An OF message object (uint8_t *)
440 * @param length The number of bytes in the message (for error checking)
441 * @param version Version of message
442 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
443 *
444 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
445 */
446
447static inline of_object_id_t
448of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
449 uint32_t experimenter_id;
450 uint32_t subtype;
451
452 /* Extract experimenter and subtype value; look for match from type maps */
453 experimenter_id = of_message_experimenter_id_get(msg);
454 subtype = of_message_experimenter_subtype_get(msg);
455
456 /* Do a simple if/else search for the ver, experimenter and subtype */
457"""
458 first = True
459 for version, experimenter_lists in type_maps.extension_message_subtype.items():
460 for exp, subtypes in experimenter_lists.items():
461 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700462 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700463 (version == %(ver_name)s)) {
464""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
465 for ext_msg, subtype in subtypes.items():
466 experimenter_function += """
467 if (subtype == %(subtype)s) {
468 return %(ext_msg)s;
469 }
470""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
471 experimenter_function += """
472 }
473"""
474 experimenter_function += """
475 return OF_EXPERIMENTER;
476}
477"""
478
479 # Message need different handling
480 msg_template = """
481/**
482 * %(name)s wire type to object ID array.
483 * Treat as private; use function accessor below
484 */
485
Rich Laneb157b0f2013-03-27 13:55:28 -0700486extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700487
488#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
489
490/**
491 * Extract the type info from the message and determine its object type
492 * @param msg An OF message object (uint8_t *)
493 * @param length The number of bytes in the message (for error checking)
494 * @returns object ID or OF_OBJECT_INVALID if parse error
495 */
496
497static inline of_object_id_t
498of_message_to_object_id(of_message_t msg, int length) {
499 uint8_t type;
500 of_version_t ver;
501 of_object_id_t obj_id;
502 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700503 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700504 uint8_t flow_mod_cmd;
505
506 if (length < OF_MESSAGE_MIN_LENGTH) {
507 return OF_OBJECT_INVALID;
508 }
509 type = of_message_type_get(msg);
510 ver = of_message_version_get(msg);
511 if (!OF_VERSION_OKAY(ver)) {
512 return OF_OBJECT_INVALID;
513 }
514
515 if (type >= OF_MESSAGE_ITEM_COUNT) {
516 return OF_OBJECT_INVALID;
517 }
518
519 obj_id = of_message_type_to_id[ver][type];
520
521 /* Remap to specific message if known */
522 if (obj_id == OF_EXPERIMENTER) {
523 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
524 return OF_OBJECT_INVALID;
525 }
526 return of_message_experimenter_to_object_id(msg, ver);
527 }
528
529 /* Remap to add/delete/strict version */
530 if (obj_id == OF_FLOW_MOD) {
531 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
532 return OF_OBJECT_INVALID;
533 }
534 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
535 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
536 }
537
538 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
539 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
540 return OF_OBJECT_INVALID;
541 }
542 stats_type = of_message_stats_type_get(msg);
543 if (obj_id == OF_STATS_REQUEST) {
544 obj_id = of_stats_request_to_object_id(stats_type, ver);
545 } else {
546 obj_id = of_stats_reply_to_object_id(stats_type, ver);
547 }
548 }
549
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700550 if (obj_id == OF_ERROR_MSG) {
551 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
552 return OF_OBJECT_INVALID;
553 }
554 err_type = of_message_error_type_get(msg);
555 obj_id = of_error_msg_to_object_id(err_type, ver);
556 }
557
Rich Lanea06d0c32013-03-25 08:52:03 -0700558 return obj_id;
559}
560"""
561
562 # Action types array gen
563 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700564 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700565 dict(name="action", u_name="ACTION", ar_len=ar_len))
566
567 # Action ID types array gen
568 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700569 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
571
572 # Instruction types array gen
573 ar_len = type_maps.type_array_len(type_maps.instruction_types,
574 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700575 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700576 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
577
578 # Queue prop types array gen
579 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
580 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700581 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700582 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
583
584 # Table feature prop types array gen
585 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
586 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700587 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700588 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
589 ar_len=ar_len))
590
591 # Meter band types array gen
592 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
593 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700594 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700595 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
596
597 # Hello elem types array gen
598 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
599 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700600 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700601 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
602
603 # Stats types array gen
604 ar_len = type_maps.type_array_len(type_maps.stats_types,
605 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700606 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700607 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700608 out.write(stats_template %
609 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700610 ar_len=ar_len))
611
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700612 ar_len = type_maps.type_array_len(type_maps.error_types,
613 max_type_value)
614 out.write(error_msg_template %
615 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
616# out.write(error_msg_function)
617
Rich Lanea06d0c32013-03-25 08:52:03 -0700618 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700619 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700620 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
621
622 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
623 out.write("""
624/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
625""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700626 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700627 dict(name="oxm", u_name="OXM", ar_len=ar_len))
628
629 out.write(experimenter_function)
630 # Must follow stats reply/request
631 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700632 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700633 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
634
635def gen_obj_to_type_map_functions(out):
636 """
637 Generate the static line maps from object IDs to types
638 @param out The file handle to write to
639 """
640
641 ################################################################
642 # Generate object ID to primary type map
643 ################################################################
644
645 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700646extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700647
648/**
649 * Map an object ID to its primary wire type value
650 * @param id An object ID
651 * @return For message objects, the type value in the OpenFlow header
652 * @return For non-message objects such as actions, instructions, OXMs
653 * returns the type value that appears in the respective sub-header
654 * @return -1 For improper version or out of bounds input
655 *
656 * NOTE that for stats request/reply, returns the header type, not the
657 * sub-type
658 *
659 * Also, note that the value is returned as a signed integer. So -1 is
660 * an error code, while 0xffff is the usual "experimenter" code.
661 */
662static inline int
663of_object_to_wire_type(of_object_id_t id, of_version_t version)
664{
665 if (!OF_VERSION_OKAY(version)) {
666 return -1;
667 }
668 if (id < 0 || id >= OF_OBJECT_COUNT) {
669 return -1;
670 }
671 return of_object_to_type_map[version][id];
672}
673
674""")
675
676 # Now for experimenter ids
677 out.write("""
678/**
679 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
680 */
681""")
682 out.write("""
683typedef struct of_experimenter_data_s {
684 int is_extension; /* Boolean indication that this is an extension */
685 uint32_t experimenter_id;
686 uint32_t subtype;
687} of_experimenter_data_t;
688
689""")
690
691 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700692extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700693
694/**
695 * Map from the object ID of an extension to the experimenter ID
696 */
697static inline uint32_t
698of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
699{
700 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
701 return (uint32_t) -1;
702 }
703 /* @fixme: Verify ver? */
704 return of_object_to_extension_data[ver][obj_id].experimenter_id;
705}
706
707/**
708 * Map from the object ID of an extension to the experimenter subtype
709 */
710static inline uint32_t
711of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
712{
713 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
714 return (uint32_t) -1;
715 }
716 /* @fixme: Verify ver? */
717 return of_object_to_extension_data[ver][obj_id].subtype;
718}
719
720/**
721 * Boolean function indicating the the given object ID/version
722 * is recognized as a supported (decode-able) extension.
723 */
724static inline int
725of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
726{
727 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
728 return (uint32_t) -1;
729 }
730 /* @fixme: Verify ver? */
731 return of_object_to_extension_data[ver][obj_id].is_extension;
732}
733""")
734
735 ################################################################
736 # Generate object ID to the stats sub-type map
737 ################################################################
738
739 out.write("""
740/**
741 * Map an object ID to a stats type
742 * @param id An object ID
743 * @return The wire value for the stats type
744 * @return -1 if not supported for this version
745 * @return -1 if id is not a specific stats type ID
746 *
747 * Note that the value is returned as a signed integer. So -1 is
748 * an error code, while 0xffff is the usual "experimenter" code.
749 */
750
751static inline int
752of_object_to_stats_type(of_object_id_t id, of_version_t version)
753{
754 if (!OF_VERSION_OKAY(version)) {
755 return -1;
756 }
757 switch (id) {
758""")
759 # Assumes 1.2 contains all stats types and type values are
760 # the same across all versions
761 stats_names = dict()
762 for ver in of_g.of_version_range:
763 for name, value in type_maps.stats_types[ver].items():
764 if name in stats_names and (not value == stats_names[name]):
765 print "ERROR stats type differ violating assumption"
766 sys.exit(1)
767 stats_names[name] = value
768
769 for name, value in stats_names.items():
770 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
771 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
772 for version in of_g.of_version_range:
773 if not name in type_maps.stats_types[version]:
774 out.write(" if (version == %s) break;\n" %
775 of_g.of_version_wire2name[version])
776 out.write(" return %d;\n" % value)
777 out.write("""
778 default:
779 break;
780 }
781 return -1; /* Not recognized as stats type object for this version */
782}
783""")
784
785 ################################################################
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700786 # Generate object ID to the error sub-type map
787 ################################################################
788 out.write("""
789/**
790 * Map an object ID to an error type
791 * @param id An object ID
792 * @return The wire value for the error type
793 * @return -1 if not supported for this version
794 * @return -1 if id is not a specific error type ID
795 *
796 * Note that the value is returned as a signed integer. So -1 is
797 * an error code, while 0xffff is the usual "experimenter" code.
798 */
799
800static inline int
801of_object_to_error_type(of_object_id_t id, of_version_t version)
802{
803 if (!OF_VERSION_OKAY(version)) {
804 return -1;
805 }
806 switch (id) {""")
807 error_names = set()
808 for ver in of_g.of_version_range:
809 for name in type_maps.error_types[ver]:
810 error_names.add(name)
811 for name in error_names:
812 out.write("""
813 case OF_%(name)s_ERROR_MSG:
814 if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
815 return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
816 break;""" % {"name": name.upper()})
817 out.write("""
818 default:
819 break;
820 }
821 return -1; /* Not recognized as error type object for this version */
822}
823""")
824
825 ################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700826 # Generate object ID to the flow mod sub-type map
827 ################################################################
828
829 out.write("""
830/**
831 * Map an object ID to a flow-mod command value
832 * @param id An object ID
833 * @return The wire value for the flow-mod command
834 * @return -1 if not supported for this version
835 * @return -1 if id is not a specific stats type ID
836 *
837 * Note that the value is returned as a signed integer. So -1 is
838 * an error code, while 0xffff is the usual "experimenter" code.
839 */
840
841static inline int
842of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
843{
844 if (!OF_VERSION_OKAY(version)) {
845 return -1;
846 }
847 switch (id) {
848""")
849 # Assumes 1.2 contains all stats types and type values are
850 # the same across all versions
851 flow_mod_names = dict()
852 for ver in of_g.of_version_range:
853 for name, value in type_maps.flow_mod_types[ver].items():
854 if name in flow_mod_names and \
855 (not value == flow_mod_names[name]):
856 print "ERROR flow mod command differ violating assumption"
857 sys.exit(1)
858 flow_mod_names[name] = value
859
860 for name, value in flow_mod_names.items():
861 out.write(" case OF_FLOW_%s:\n" % name.upper())
862 for version in of_g.of_version_range:
863 if not name in type_maps.flow_mod_types[version]:
864 out.write(" if (version == %s) break;\n" %
865 of_g.of_version_wire2name[version])
866 out.write(" return %d;\n" % value)
867 out.write("""
868 default:
869 break;
870 }
871 return -1; /* Not recognized as flow mod type object for this version */
872}
873
874""")
875
876def gen_type_maps_header(out):
877 """
878 Generate various header file declarations for type maps
879 @param out The file handle to write to
880 """
881
882 out.write("""
883/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700884 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700885 * top level message: Action, instruction, error, stats, queue_props, oxm
886 */
887#define OF_EXPERIMENTER_TYPE 0xffff
888""")
889 gen_type_to_obj_map_functions(out)
890 gen_obj_to_type_map_functions(out)
891
Rich Laneb157b0f2013-03-27 13:55:28 -0700892 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700893 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700894
895 out.write("""
896/**
897 * Map a message in a wire buffer object to its OF object id.
898 * @param wbuf Pointer to a wire buffer object, populated with an OF message
899 * @returns The object ID of the message
900 * @returns OF_OBJECT_INVALID if unable to parse the message type
901 */
902
903static inline of_object_id_t
904of_wire_object_id_get(of_wire_buffer_t *wbuf)
905{
906 of_message_t msg;
907
908 msg = (of_message_t)WBUF_BUF(wbuf);
909 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
910}
911
912/**
913 * Use the type/length from the wire buffer and init the object
914 * @param obj The object being initialized
915 * @param base_object_id If > 0, this indicates the base object
916 * @param max_len If > 0, the max length to expect for the obj
917 * type for inheritance checking
918 * @return OF_ERROR_
919 *
920 * Used for inheritance type objects such as actions and OXMs
921 * The type is checked and if valid, the object is initialized.
922 * Then the length is taken from the buffer.
923 *
924 * Note that the object version must already be properly set.
925 */
926static inline int
927of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
928 int max_len)
929{
930 if (obj->wire_type_get != NULL) {
931 of_object_id_t id;
932 obj->wire_type_get(obj, &id);
933 if (!of_wire_id_valid(id, base_object_id)) {
934 return OF_ERROR_PARSE;
935 }
936 obj->object_id = id;
937 /* Call the init function for this object type; do not push to wire */
938 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
939 }
940 if (obj->wire_length_get != NULL) {
941 int length;
942 obj->wire_length_get(obj, &length);
943 if (length < 0 || (max_len > 0 && length > max_len)) {
944 return OF_ERROR_PARSE;
945 }
946 obj->length = length;
947 } else {
948 /* @fixme Does this cover everything else? */
949 obj->length = of_object_fixed_len[obj->version][base_object_id];
950 }
951
952 return OF_ERROR_NONE;
953}
954
955""")
956
957 # Generate the function that sets the object type fields
958 out.write("""
959
960/**
961 * Map a message in a wire buffer object to its OF object id.
962 * @param wbuf Pointer to a wire buffer object, populated with an OF message
963 * @returns The object ID of the message
964 * @returns OF_OBJECT_INVALID if unable to parse the message type
965 *
966 * Version must be set in the buffer prior to calling this routine
967 */
968
969static inline int
970of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
971{
972 int type;
973 of_version_t ver;
974 of_message_t msg;
975
976 msg = (of_message_t)WBUF_BUF(wbuf);
977
978 ver = of_message_version_get(msg);
979
980 /* ASSERT(id is a message object) */
981
982 if ((type = of_object_to_wire_type(id, ver)) < 0) {
983 return OF_ERROR_PARAM;
984 }
985 of_message_type_set(msg, type);
986
987 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
988 /* It's a stats obj */
989 of_message_stats_type_set(msg, type);
990 }
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700991 if ((type = of_object_to_error_type(id, ver)) >= 0) {
992 /* It's a stats obj */
993 of_message_error_type_set(msg, type);
994 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700995 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
996 /* It's a flow mod obj */
997 of_message_flow_mod_command_set(msg, ver, type);
998 }
999 if (of_object_id_is_extension(id, ver)) {
1000 uint32_t val32;
1001
1002 /* Set the experimenter and subtype codes */
1003 val32 = of_extension_to_experimenter_id(id, ver);
1004 of_message_experimenter_id_set(msg, val32);
1005 val32 = of_extension_to_experimenter_subtype(id, ver);
1006 of_message_experimenter_subtype_set(msg, val32);
1007 }
1008
1009 return OF_ERROR_NONE;
1010}
1011""")
1012
1013def gen_type_data_header(out):
1014
1015 out.write("""
1016/****************************************************************
1017 *
1018 * The following declarations are for type and length calculations.
1019 * Implementations may be found in of_type_maps.c
1020 *
1021 ****************************************************************/
1022/*
1023 * Special case length functions for objects with
1024 */
1025""")
1026 for ((cls, name), prev) in of_g.special_offsets.items():
1027 s_cls = cls[3:] # take off of_
1028 out.write("""
1029/**
1030 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001031 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001032 * length of %(name)s
1033 * @param bytes[out] Where to store the calculated length
1034 *
1035 * Preceding data member is %(prev)s.
1036 */
1037extern int of_length_%(s_cls)s_%(name)s_get(
1038 %(cls)s_t *obj, int *bytes);
1039
1040/**
1041 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -07001042 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -07001043 * length of %(name)s
1044 * @param offset[out] Where to store the calculated length
1045 *
1046 * Preceding data member is %(prev)s.
1047 */
1048extern int of_offset_%(s_cls)s_%(name)s_get(
1049 %(cls)s_t *obj, int *offset);
1050""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
1051
1052# NOT NEEDED YET
1053# # For non-message, variable length objects, give a fun that
1054# # calculates the length
1055# for cls in of_g.standard_class_order:
1056# s_cls = cls[3:] # take off of_
1057# if !type_is_var_len(cls, version):
1058# continue
1059# out.write("""
1060# /**
1061# * Special length calculation for variable length object %(cls)s
1062# * @param obj An object of type %(cls)s whose length is being calculated
1063# * @param bytes[out] Where to store the calculated length
1064# *
1065# * The assumption is that the length member of the object is not
1066# * valid and the length needs to be calculated from other information
1067# * such as the parent.
1068# */
1069# extern int of_length_%(s_cls)s_get(
1070# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -07001071# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001072
1073 out.write("""
1074/****************************************************************
1075 * Wire type/length functions.
1076 ****************************************************************/
1077
1078extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
1079extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
1080
1081extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
1082extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
1083extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1084extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1085
1086extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
1087extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
1088
1089extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
1090
1091/* Wire length is uint16 at front of structure */
1092extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
1093extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
1094
1095extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
1096extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001097extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001098 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001099extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001100 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001101extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001102 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001103extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001104 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001105extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001106 of_object_id_t *id);
1107
Rich Lane47085722013-07-12 16:27:04 -07001108/* XXX Hardcoded to the OpenFlow Basic OXM class */
Rich Lanea06d0c32013-03-25 08:52:03 -07001109#define OF_OXM_MASKED_TYPE_GET(hdr) (((hdr) >> 8) & 0xff)
1110#define OF_OXM_MASKED_TYPE_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001111 (hdr) = ((hdr) & 0x000000ff) + 0x80000000 + (((val) & 0xff) << 8)
Rich Lanea06d0c32013-03-25 08:52:03 -07001112
Rich Lane47085722013-07-12 16:27:04 -07001113#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -07001114#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -07001115 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -07001116
1117extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1118extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1119
1120extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1121 int *bytes);
1122extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1123extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1124extern int of_extension_object_wire_push(of_object_t *obj);
1125
1126""")
1127
1128
1129def gen_length_array(out):
1130 """
1131 Generate an array giving the lengths of all objects/versions
1132 @param out The file handle to which to write
1133 """
1134 out.write("""
1135/**
1136 * An array with the number of bytes in the fixed length part
1137 * of each OF object
1138 */
1139""")
1140
1141 for version in of_g.of_version_range:
1142 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001143static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001144 -1, /* of_object is not instantiable */
1145""" % version)
1146 for i, cls in enumerate(of_g.all_class_order):
1147 comma = ","
1148 if i == len(of_g.all_class_order) - 1:
1149 comma = ""
1150 val = "-1" + comma
1151 if (cls, version) in of_g.base_length:
1152 val = str(of_g.base_length[(cls, version)]) + comma
1153 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1154 out.write("};\n")
1155
1156 out.write("""
1157/**
1158 * Unified map of fixed length part of each object
1159 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001160const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001161 NULL,
1162""")
1163 for version in of_g.of_version_range:
1164 out.write(" of_object_fixed_len_v%d,\n" % version)
1165 out.write("""
1166};
1167""")
1168
Andreas Wundsam53256162013-05-02 14:05:53 -07001169
Rich Lanef70be942013-07-18 13:33:14 -07001170def gen_extra_length_array(out):
1171 """
1172 Generate an array giving the extra lengths of all objects/versions
1173 @param out The file handle to which to write
1174 """
1175 out.write("""
1176/**
1177 * An array with the number of bytes in the extra length part
1178 * of each OF object
1179 */
1180""")
1181
1182 for version in of_g.of_version_range:
1183 out.write("""
1184static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
1185 -1, /* of_object is not instantiable */
1186""" % version)
1187 for i, cls in enumerate(of_g.all_class_order):
1188 comma = ","
1189 if i == len(of_g.all_class_order) - 1:
1190 comma = ""
1191 val = "-1" + comma
1192 if (cls, version) in of_g.base_length:
1193 val = str(of_g.extra_length.get((cls, version), 0)) + comma
1194 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1195 out.write("};\n")
1196
1197 out.write("""
1198/**
1199 * Unified map of extra length part of each object
1200 */
1201const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
1202 NULL,
1203""")
1204 for version in of_g.of_version_range:
1205 out.write(" of_object_extra_len_v%d,\n" % version)
1206 out.write("""
1207};
1208""")
1209
1210
Rich Lanea06d0c32013-03-25 08:52:03 -07001211################################################################
1212################################################################
1213
1214# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1215def gen_object_id_to_stats_type(out):
1216 out.write("""
1217/**
1218 * Map from message object ID to stats type
1219 *
1220 * All message object IDs are mapped for simplicity
1221 */
1222""")
1223 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001224 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001225 out.write(" -1, /* of_object (invalid) */\n");
1226 for cls in of_g.ordered_messages:
1227 name = cls[3:]
1228 name = name[:name.find("_stats")]
1229 if (((cls in type_maps.stats_reply_list) or
1230 (cls in type_maps.stats_request_list)) and
1231 name in type_maps.stats_types[i]):
1232 out.write(" %d, /* %s */\n" %
1233 (type_maps.stats_types[i][name], cls))
1234 else:
1235 out.write(" -1, /* %s (invalid) */\n" % cls)
1236 out.write("};\n\n")
1237
1238 out.write("""
1239/**
1240 * Unified map, indexed by wire version which is 1-based.
1241 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001242const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001243 NULL,
1244""")
1245 for version in of_g.of_version_range:
1246 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1247 out.write("""
1248};
1249""")
1250