blob: 6cbf7bcd5b87e9c73ab909dc4906ec4d0064060d [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))
70 elif cls in type_maps.flow_mod_list:
Andreas Wundsam53256162013-05-02 14:05:53 -070071 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070072 (type_maps.type_val[("of_flow_mod", version)],
73 comma, cls))
74 elif (cls, version) in type_maps.type_val:
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[(cls, version)], comma, cls))
77 elif type_maps.message_is_extension(cls, version):
Andreas Wundsam53256162013-05-02 14:05:53 -070078 out.write(" %d%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070079 (type_maps.type_val[("of_experimenter", version)],
80 comma, cls))
81 elif type_maps.action_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_action_experimenter",
84 version)],
85 comma, cls))
86 elif type_maps.action_id_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_id_experimenter",
89 version)],
90 comma, cls))
91 elif type_maps.instruction_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_instruction_experimenter",
94 version)],
95 comma, cls))
96 elif type_maps.queue_prop_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_queue_prop_experimenter",
99 version)],
100 comma, cls))
101 elif type_maps.table_feature_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_table_feature_prop_experimenter",
104 version)],
105 comma, cls))
106 else:
107 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
108 out.write("};\n\n")
109
110 out.write("""
111/**
112 * Unified map, indexed by wire version which is 1-based.
113 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700114const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700115 NULL,
116""")
117 for version in of_g.of_version_range:
118 out.write(" of_object_to_type_map_v%d,\n" % version)
119 out.write("""
120};
121""")
122
123def gen_object_id_to_extension_data(out):
124 out.write("""
125/**
126 * Extension data.
127 * @fixme There must be a better way to represent this data
128 */
129""")
130 for version in of_g.of_version_range:
131 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700132static const of_experimenter_data_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700133of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
134""" % version)
135 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
136 for j, cls in enumerate(of_g.all_class_order):
137 comma = ""
138 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
139 comma = ","
140
141 if type_maps.class_is_extension(cls, version):
142 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
143 subtype = type_maps.extension_to_subtype(cls, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700144 out.write(" {1, %s, %d}%s /* %s */\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700145 (exp_name, subtype, comma, cls))
146 else:
147 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
148 (comma, cls))
149 out.write("};\n\n")
150
151 out.write("""
152/**
153 * Unified map, indexed by wire version which is 1-based.
154 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700155const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 NULL,
157""")
158 for version in of_g.of_version_range:
159 out.write(" of_object_to_extension_data_v%d,\n" % version)
160 out.write("""
161};
162""")
163
164def gen_type_to_object_id(out, type_str, prefix, template,
165 value_array, max_val):
166 """
167 Generate C maps from various message class groups to object ids
168
169 For each version, create an array mapping the type info to the
170 object ID. Then define an array containing those pointers.
171 """
172
173 # Create unified arrays and get length
174 arr_len = type_maps.type_array_len(value_array, max_val)
175 all_ars = []
176 for version, val_dict in value_array.items(): # Per version dict
177 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
178 all_ars.append(ar)
179
180 len_name = "%s_ITEM_COUNT" % prefix
181
182 for i, ar in enumerate(all_ars):
183 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -0700184 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -0700185 (type_str, version, len_name))
186 for i in range(arr_len):
187 comma = ""
188 if i < arr_len - 1: # Avoid ultimate comma
189 comma = ","
190
191 # Per-version length check
192 if i < len(ar):
193 v = ar[i]
194 else:
195 v = type_maps.invalid_type
196
197 if v == type_maps.invalid_type:
198 out.write(" %-30s /* %d (Invalid) */\n" %
199 ("OF_OBJECT_INVALID" + comma, i))
200 else:
201 name = (template % v.upper()) + comma
202 out.write(" %-30s /* %d */\n" % (name, i))
203 out.write("};\n")
204
205 out.write("""
206/**
207 * Maps from %(c_name)s wire type values to LOCI object ids
208 *
209 * Indexed by wire version which is 1-based.
210 */
211
Rich Laneb157b0f2013-03-27 13:55:28 -0700212const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700213 NULL,
214""" % dict(name=type_str, c_name=prefix.lower()))
215 for version in of_g.of_version_range:
216 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
217 version=version))
218 out.write("""
219};
220
Andreas Wundsam53256162013-05-02 14:05:53 -0700221""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700222 max_val=max_val, c_name=prefix.lower()))
223
224def gen_type_maps(out):
225 """
226 Generate various type maps
227 @param out The file handle to write to
228 """
229
230 out.write("#include <loci/loci.h>\n\n")
231
232 # Generate maps from wire type values to object IDs
233 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
234 "OF_ACTION_%s", type_maps.action_types,
235 max_type_value)
236 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
237 "OF_ACTION_ID_%s", type_maps.action_id_types,
238 max_type_value)
239 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700240 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700241 max_type_value)
242 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
243 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
244 max_type_value)
245 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
246 "OF_TABLE_FEATURE_PROP",
247 "OF_TABLE_FEATURE_PROP_%s",
248 type_maps.table_feature_prop_types,
249 max_type_value)
250 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
251 "OF_METER_BAND_%s", type_maps.meter_band_types,
252 max_type_value)
253 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
254 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
255 max_type_value)
256
257 # FIXME: Multipart re-organization
258 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
259 "OF_%s_STATS_REQUEST", type_maps.stats_types,
260 max_type_value)
261 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
262 "OF_%s_STATS_REPLY", type_maps.stats_types,
263 max_type_value)
264 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
265 "OF_FLOW_%s", type_maps.flow_mod_types,
266 max_type_value)
267 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
268 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
269 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
270 "OF_%s", type_maps.message_types, max_type_value)
271
272 gen_object_id_to_type(out)
273 gen_object_id_to_extension_data(out)
274 # Don't need array mapping ID to stats types right now; handled directly
275 # gen_object_id_to_stats_type(out)
276
277
278def gen_type_to_obj_map_functions(out):
279 """
280 Generate the templated static inline type map functions
281 @param out The file handle to write to
282 """
283
284 ################################################################
285 # Generate all type-to-object-ID maps in a common way
286 ################################################################
287 map_template = """
288/**
289 * %(name)s wire type to object ID array.
290 * Treat as private; use function accessor below
291 */
292
Rich Laneb157b0f2013-03-27 13:55:28 -0700293extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700294
295#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
296
297/**
298 * Map an %(name)s wire value to an OF object
299 * @param %(name)s The %(name)s type wire value
300 * @param version The version associated with the check
301 * @return The %(name)s OF object type
302 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700303 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700304 */
305static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700306of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700307{
308 if (!OF_VERSION_OKAY(version)) {
309 return OF_OBJECT_INVALID;
310 }
311 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
312 return OF_OBJECT_INVALID;
313 }
314
315 return of_%(name)s_type_to_id[version][%(name)s];
316}
317"""
318 map_with_experimenter_template = """
319/**
320 * %(name)s wire type to object ID array.
321 * Treat as private; use function accessor below
322 */
323
Rich Laneb157b0f2013-03-27 13:55:28 -0700324extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700325
326#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
327
328/**
329 * Map an %(name)s wire value to an OF object
330 * @param %(name)s The %(name)s type wire value
331 * @param version The version associated with the check
332 * @return The %(name)s OF object type
333 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700334 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700335 */
336static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700337of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700338{
339 if (!OF_VERSION_OKAY(version)) {
340 return OF_OBJECT_INVALID;
341 }
342 if (%(name)s == OF_EXPERIMENTER_TYPE) {
343 return OF_%(u_name)s_EXPERIMENTER;
344 }
345 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
346 return OF_OBJECT_INVALID;
347 }
348
349 return of_%(name)s_type_to_id[version][%(name)s];
350}
351"""
352
353 stats_template = """
354/**
355 * %(name)s wire type to object ID array.
356 * Treat as private; use function accessor below
357 */
358
Rich Laneb157b0f2013-03-27 13:55:28 -0700359extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700360
361#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
362
363/**
364 * Map an %(name)s wire value to an OF object
365 * @param %(name)s The %(name)s type wire value
366 * @param version The version associated with the check
367 * @return The %(name)s OF object type
368 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700369 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700370 */
371static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700372of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700373{
374 if (!OF_VERSION_OKAY(version)) {
375 return OF_OBJECT_INVALID;
376 }
377 if (%(name)s == OF_EXPERIMENTER_TYPE) {
378 return OF_EXPERIMENTER_%(u_name)s;
379 }
380 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
381 return OF_OBJECT_INVALID;
382 }
383
384 return of_%(name)s_type_to_id[version][%(name)s];
385}
386"""
387 # Experimenter mapping functions
388 # Currently we support very few candidates, so we just do a
389 # list of if/elses
390 experimenter_function = """
391/**
392 * @brief Map a message known to be an exp msg to the proper object
393 *
394 * Assume that the message is a vendor/experimenter message. Determine
395 * the specific object type for the message.
396 * @param msg An OF message object (uint8_t *)
397 * @param length The number of bytes in the message (for error checking)
398 * @param version Version of message
399 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
400 *
401 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
402 */
403
404static inline of_object_id_t
405of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
406 uint32_t experimenter_id;
407 uint32_t subtype;
408
409 /* Extract experimenter and subtype value; look for match from type maps */
410 experimenter_id = of_message_experimenter_id_get(msg);
411 subtype = of_message_experimenter_subtype_get(msg);
412
413 /* Do a simple if/else search for the ver, experimenter and subtype */
414"""
415 first = True
416 for version, experimenter_lists in type_maps.extension_message_subtype.items():
417 for exp, subtypes in experimenter_lists.items():
418 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700419 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700420 (version == %(ver_name)s)) {
421""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
422 for ext_msg, subtype in subtypes.items():
423 experimenter_function += """
424 if (subtype == %(subtype)s) {
425 return %(ext_msg)s;
426 }
427""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
428 experimenter_function += """
429 }
430"""
431 experimenter_function += """
432 return OF_EXPERIMENTER;
433}
434"""
435
436 # Message need different handling
437 msg_template = """
438/**
439 * %(name)s wire type to object ID array.
440 * Treat as private; use function accessor below
441 */
442
Rich Laneb157b0f2013-03-27 13:55:28 -0700443extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700444
445#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
446
447/**
448 * Extract the type info from the message and determine its object type
449 * @param msg An OF message object (uint8_t *)
450 * @param length The number of bytes in the message (for error checking)
451 * @returns object ID or OF_OBJECT_INVALID if parse error
452 */
453
454static inline of_object_id_t
455of_message_to_object_id(of_message_t msg, int length) {
456 uint8_t type;
457 of_version_t ver;
458 of_object_id_t obj_id;
459 uint16_t stats_type;
460 uint8_t flow_mod_cmd;
461
462 if (length < OF_MESSAGE_MIN_LENGTH) {
463 return OF_OBJECT_INVALID;
464 }
465 type = of_message_type_get(msg);
466 ver = of_message_version_get(msg);
467 if (!OF_VERSION_OKAY(ver)) {
468 return OF_OBJECT_INVALID;
469 }
470
471 if (type >= OF_MESSAGE_ITEM_COUNT) {
472 return OF_OBJECT_INVALID;
473 }
474
475 obj_id = of_message_type_to_id[ver][type];
476
477 /* Remap to specific message if known */
478 if (obj_id == OF_EXPERIMENTER) {
479 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
480 return OF_OBJECT_INVALID;
481 }
482 return of_message_experimenter_to_object_id(msg, ver);
483 }
484
485 /* Remap to add/delete/strict version */
486 if (obj_id == OF_FLOW_MOD) {
487 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
488 return OF_OBJECT_INVALID;
489 }
490 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
491 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
492 }
493
494 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
495 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
496 return OF_OBJECT_INVALID;
497 }
498 stats_type = of_message_stats_type_get(msg);
499 if (obj_id == OF_STATS_REQUEST) {
500 obj_id = of_stats_request_to_object_id(stats_type, ver);
501 } else {
502 obj_id = of_stats_reply_to_object_id(stats_type, ver);
503 }
504 }
505
506 return obj_id;
507}
508"""
509
510 # Action types array gen
511 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700512 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700513 dict(name="action", u_name="ACTION", ar_len=ar_len))
514
515 # Action ID types array gen
516 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700517 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700518 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
519
520 # Instruction types array gen
521 ar_len = type_maps.type_array_len(type_maps.instruction_types,
522 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700523 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700524 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
525
526 # Queue prop types array gen
527 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
528 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700529 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700530 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
531
532 # Table feature prop types array gen
533 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
534 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700535 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700536 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
537 ar_len=ar_len))
538
539 # Meter band types array gen
540 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
541 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700542 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700543 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
544
545 # Hello elem types array gen
546 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
547 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700548 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700549 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
550
551 # Stats types array gen
552 ar_len = type_maps.type_array_len(type_maps.stats_types,
553 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700554 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700555 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700556 out.write(stats_template %
557 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700558 ar_len=ar_len))
559
560 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700561 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
563
564 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
565 out.write("""
566/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
567""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700568 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700569 dict(name="oxm", u_name="OXM", ar_len=ar_len))
570
571 out.write(experimenter_function)
572 # Must follow stats reply/request
573 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700574 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700575 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
576
577def gen_obj_to_type_map_functions(out):
578 """
579 Generate the static line maps from object IDs to types
580 @param out The file handle to write to
581 """
582
583 ################################################################
584 # Generate object ID to primary type map
585 ################################################################
586
587 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700588extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700589
590/**
591 * Map an object ID to its primary wire type value
592 * @param id An object ID
593 * @return For message objects, the type value in the OpenFlow header
594 * @return For non-message objects such as actions, instructions, OXMs
595 * returns the type value that appears in the respective sub-header
596 * @return -1 For improper version or out of bounds input
597 *
598 * NOTE that for stats request/reply, returns the header type, not the
599 * sub-type
600 *
601 * Also, note that the value is returned as a signed integer. So -1 is
602 * an error code, while 0xffff is the usual "experimenter" code.
603 */
604static inline int
605of_object_to_wire_type(of_object_id_t id, of_version_t version)
606{
607 if (!OF_VERSION_OKAY(version)) {
608 return -1;
609 }
610 if (id < 0 || id >= OF_OBJECT_COUNT) {
611 return -1;
612 }
613 return of_object_to_type_map[version][id];
614}
615
616""")
617
618 # Now for experimenter ids
619 out.write("""
620/**
621 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
622 */
623""")
624 out.write("""
625typedef struct of_experimenter_data_s {
626 int is_extension; /* Boolean indication that this is an extension */
627 uint32_t experimenter_id;
628 uint32_t subtype;
629} of_experimenter_data_t;
630
631""")
632
633 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700634extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700635
636/**
637 * Map from the object ID of an extension to the experimenter ID
638 */
639static inline uint32_t
640of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
641{
642 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
643 return (uint32_t) -1;
644 }
645 /* @fixme: Verify ver? */
646 return of_object_to_extension_data[ver][obj_id].experimenter_id;
647}
648
649/**
650 * Map from the object ID of an extension to the experimenter subtype
651 */
652static inline uint32_t
653of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
654{
655 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
656 return (uint32_t) -1;
657 }
658 /* @fixme: Verify ver? */
659 return of_object_to_extension_data[ver][obj_id].subtype;
660}
661
662/**
663 * Boolean function indicating the the given object ID/version
664 * is recognized as a supported (decode-able) extension.
665 */
666static inline int
667of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
668{
669 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
670 return (uint32_t) -1;
671 }
672 /* @fixme: Verify ver? */
673 return of_object_to_extension_data[ver][obj_id].is_extension;
674}
675""")
676
677 ################################################################
678 # Generate object ID to the stats sub-type map
679 ################################################################
680
681 out.write("""
682/**
683 * Map an object ID to a stats type
684 * @param id An object ID
685 * @return The wire value for the stats type
686 * @return -1 if not supported for this version
687 * @return -1 if id is not a specific stats type ID
688 *
689 * Note that the value is returned as a signed integer. So -1 is
690 * an error code, while 0xffff is the usual "experimenter" code.
691 */
692
693static inline int
694of_object_to_stats_type(of_object_id_t id, of_version_t version)
695{
696 if (!OF_VERSION_OKAY(version)) {
697 return -1;
698 }
699 switch (id) {
700""")
701 # Assumes 1.2 contains all stats types and type values are
702 # the same across all versions
703 stats_names = dict()
704 for ver in of_g.of_version_range:
705 for name, value in type_maps.stats_types[ver].items():
706 if name in stats_names and (not value == stats_names[name]):
707 print "ERROR stats type differ violating assumption"
708 sys.exit(1)
709 stats_names[name] = value
710
711 for name, value in stats_names.items():
712 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
713 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
714 for version in of_g.of_version_range:
715 if not name in type_maps.stats_types[version]:
716 out.write(" if (version == %s) break;\n" %
717 of_g.of_version_wire2name[version])
718 out.write(" return %d;\n" % value)
719 out.write("""
720 default:
721 break;
722 }
723 return -1; /* Not recognized as stats type object for this version */
724}
725""")
726
727 ################################################################
728 # Generate object ID to the flow mod sub-type map
729 ################################################################
730
731 out.write("""
732/**
733 * Map an object ID to a flow-mod command value
734 * @param id An object ID
735 * @return The wire value for the flow-mod command
736 * @return -1 if not supported for this version
737 * @return -1 if id is not a specific stats type ID
738 *
739 * Note that the value is returned as a signed integer. So -1 is
740 * an error code, while 0xffff is the usual "experimenter" code.
741 */
742
743static inline int
744of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
745{
746 if (!OF_VERSION_OKAY(version)) {
747 return -1;
748 }
749 switch (id) {
750""")
751 # Assumes 1.2 contains all stats types and type values are
752 # the same across all versions
753 flow_mod_names = dict()
754 for ver in of_g.of_version_range:
755 for name, value in type_maps.flow_mod_types[ver].items():
756 if name in flow_mod_names and \
757 (not value == flow_mod_names[name]):
758 print "ERROR flow mod command differ violating assumption"
759 sys.exit(1)
760 flow_mod_names[name] = value
761
762 for name, value in flow_mod_names.items():
763 out.write(" case OF_FLOW_%s:\n" % name.upper())
764 for version in of_g.of_version_range:
765 if not name in type_maps.flow_mod_types[version]:
766 out.write(" if (version == %s) break;\n" %
767 of_g.of_version_wire2name[version])
768 out.write(" return %d;\n" % value)
769 out.write("""
770 default:
771 break;
772 }
773 return -1; /* Not recognized as flow mod type object for this version */
774}
775
776""")
777
778def gen_type_maps_header(out):
779 """
780 Generate various header file declarations for type maps
781 @param out The file handle to write to
782 """
783
784 out.write("""
785/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700786 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700787 * top level message: Action, instruction, error, stats, queue_props, oxm
788 */
789#define OF_EXPERIMENTER_TYPE 0xffff
790""")
791 gen_type_to_obj_map_functions(out)
792 gen_obj_to_type_map_functions(out)
793
Rich Laneb157b0f2013-03-27 13:55:28 -0700794 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700795
796 out.write("""
797/**
798 * Map a message in a wire buffer object to its OF object id.
799 * @param wbuf Pointer to a wire buffer object, populated with an OF message
800 * @returns The object ID of the message
801 * @returns OF_OBJECT_INVALID if unable to parse the message type
802 */
803
804static inline of_object_id_t
805of_wire_object_id_get(of_wire_buffer_t *wbuf)
806{
807 of_message_t msg;
808
809 msg = (of_message_t)WBUF_BUF(wbuf);
810 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
811}
812
813/**
814 * Use the type/length from the wire buffer and init the object
815 * @param obj The object being initialized
816 * @param base_object_id If > 0, this indicates the base object
817 * @param max_len If > 0, the max length to expect for the obj
818 * type for inheritance checking
819 * @return OF_ERROR_
820 *
821 * Used for inheritance type objects such as actions and OXMs
822 * The type is checked and if valid, the object is initialized.
823 * Then the length is taken from the buffer.
824 *
825 * Note that the object version must already be properly set.
826 */
827static inline int
828of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
829 int max_len)
830{
831 if (obj->wire_type_get != NULL) {
832 of_object_id_t id;
833 obj->wire_type_get(obj, &id);
834 if (!of_wire_id_valid(id, base_object_id)) {
835 return OF_ERROR_PARSE;
836 }
837 obj->object_id = id;
838 /* Call the init function for this object type; do not push to wire */
839 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
840 }
841 if (obj->wire_length_get != NULL) {
842 int length;
843 obj->wire_length_get(obj, &length);
844 if (length < 0 || (max_len > 0 && length > max_len)) {
845 return OF_ERROR_PARSE;
846 }
847 obj->length = length;
848 } else {
849 /* @fixme Does this cover everything else? */
850 obj->length = of_object_fixed_len[obj->version][base_object_id];
851 }
852
853 return OF_ERROR_NONE;
854}
855
856""")
857
858 # Generate the function that sets the object type fields
859 out.write("""
860
861/**
862 * Map a message in a wire buffer object to its OF object id.
863 * @param wbuf Pointer to a wire buffer object, populated with an OF message
864 * @returns The object ID of the message
865 * @returns OF_OBJECT_INVALID if unable to parse the message type
866 *
867 * Version must be set in the buffer prior to calling this routine
868 */
869
870static inline int
871of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
872{
873 int type;
874 of_version_t ver;
875 of_message_t msg;
876
877 msg = (of_message_t)WBUF_BUF(wbuf);
878
879 ver = of_message_version_get(msg);
880
881 /* ASSERT(id is a message object) */
882
883 if ((type = of_object_to_wire_type(id, ver)) < 0) {
884 return OF_ERROR_PARAM;
885 }
886 of_message_type_set(msg, type);
887
888 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
889 /* It's a stats obj */
890 of_message_stats_type_set(msg, type);
891 }
892 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
893 /* It's a flow mod obj */
894 of_message_flow_mod_command_set(msg, ver, type);
895 }
896 if (of_object_id_is_extension(id, ver)) {
897 uint32_t val32;
898
899 /* Set the experimenter and subtype codes */
900 val32 = of_extension_to_experimenter_id(id, ver);
901 of_message_experimenter_id_set(msg, val32);
902 val32 = of_extension_to_experimenter_subtype(id, ver);
903 of_message_experimenter_subtype_set(msg, val32);
904 }
905
906 return OF_ERROR_NONE;
907}
908""")
909
910def gen_type_data_header(out):
911
912 out.write("""
913/****************************************************************
914 *
915 * The following declarations are for type and length calculations.
916 * Implementations may be found in of_type_maps.c
917 *
918 ****************************************************************/
919/*
920 * Special case length functions for objects with
921 */
922""")
923 for ((cls, name), prev) in of_g.special_offsets.items():
924 s_cls = cls[3:] # take off of_
925 out.write("""
926/**
927 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700928 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700929 * length of %(name)s
930 * @param bytes[out] Where to store the calculated length
931 *
932 * Preceding data member is %(prev)s.
933 */
934extern int of_length_%(s_cls)s_%(name)s_get(
935 %(cls)s_t *obj, int *bytes);
936
937/**
938 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700939 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700940 * length of %(name)s
941 * @param offset[out] Where to store the calculated length
942 *
943 * Preceding data member is %(prev)s.
944 */
945extern int of_offset_%(s_cls)s_%(name)s_get(
946 %(cls)s_t *obj, int *offset);
947""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
948
949# NOT NEEDED YET
950# # For non-message, variable length objects, give a fun that
951# # calculates the length
952# for cls in of_g.standard_class_order:
953# s_cls = cls[3:] # take off of_
954# if !type_is_var_len(cls, version):
955# continue
956# out.write("""
957# /**
958# * Special length calculation for variable length object %(cls)s
959# * @param obj An object of type %(cls)s whose length is being calculated
960# * @param bytes[out] Where to store the calculated length
961# *
962# * The assumption is that the length member of the object is not
963# * valid and the length needs to be calculated from other information
964# * such as the parent.
965# */
966# extern int of_length_%(s_cls)s_get(
967# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -0700968# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -0700969
970 out.write("""
971/****************************************************************
972 * Wire type/length functions.
973 ****************************************************************/
974
975extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
976extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
977
978extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
979extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
980extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
981extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
982
983extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
984extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
985
986extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
987
988/* Wire length is uint16 at front of structure */
989extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
990extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
991
992extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
993extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700994extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700995 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700996extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700997 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700998extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700999 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001000extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001001 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -07001002extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001003 of_object_id_t *id);
1004
1005/** @fixme VERIFY LENGTH IS NUMBER OF BYTES OF ENTRY INCLUDING HDR */
1006#define OF_OXM_MASKED_TYPE_GET(hdr) (((hdr) >> 8) & 0xff)
1007#define OF_OXM_MASKED_TYPE_SET(hdr, val) \\
1008 (hdr) = ((hdr) & 0xffff00ff) + (((val) & 0xff) << 8)
1009
1010#define OF_OXM_LENGTH_GET(hdr) ((hdr) & 0xff)
1011#define OF_OXM_LENGTH_SET(hdr, val) \\
1012 (hdr) = ((hdr) & 0xffffff00) + ((val) & 0xff)
1013
1014extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1015extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1016
1017extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1018 int *bytes);
1019extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1020extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1021extern int of_extension_object_wire_push(of_object_t *obj);
1022
1023""")
1024
1025
1026def gen_length_array(out):
1027 """
1028 Generate an array giving the lengths of all objects/versions
1029 @param out The file handle to which to write
1030 """
1031 out.write("""
1032/**
1033 * An array with the number of bytes in the fixed length part
1034 * of each OF object
1035 */
1036""")
1037
1038 for version in of_g.of_version_range:
1039 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001040static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001041 -1, /* of_object is not instantiable */
1042""" % version)
1043 for i, cls in enumerate(of_g.all_class_order):
1044 comma = ","
1045 if i == len(of_g.all_class_order) - 1:
1046 comma = ""
1047 val = "-1" + comma
1048 if (cls, version) in of_g.base_length:
1049 val = str(of_g.base_length[(cls, version)]) + comma
1050 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1051 out.write("};\n")
1052
1053 out.write("""
1054/**
1055 * Unified map of fixed length part of each object
1056 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001057const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001058 NULL,
1059""")
1060 for version in of_g.of_version_range:
1061 out.write(" of_object_fixed_len_v%d,\n" % version)
1062 out.write("""
1063};
1064""")
1065
Andreas Wundsam53256162013-05-02 14:05:53 -07001066
Rich Lanea06d0c32013-03-25 08:52:03 -07001067################################################################
1068################################################################
1069
1070# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1071def gen_object_id_to_stats_type(out):
1072 out.write("""
1073/**
1074 * Map from message object ID to stats type
1075 *
1076 * All message object IDs are mapped for simplicity
1077 */
1078""")
1079 for version in of_g.of_version_range:
Rich Laneb157b0f2013-03-27 13:55:28 -07001080 out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
Rich Lanea06d0c32013-03-25 08:52:03 -07001081 out.write(" -1, /* of_object (invalid) */\n");
1082 for cls in of_g.ordered_messages:
1083 name = cls[3:]
1084 name = name[:name.find("_stats")]
1085 if (((cls in type_maps.stats_reply_list) or
1086 (cls in type_maps.stats_request_list)) and
1087 name in type_maps.stats_types[i]):
1088 out.write(" %d, /* %s */\n" %
1089 (type_maps.stats_types[i][name], cls))
1090 else:
1091 out.write(" -1, /* %s (invalid) */\n" % cls)
1092 out.write("};\n\n")
1093
1094 out.write("""
1095/**
1096 * Unified map, indexed by wire version which is 1-based.
1097 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001098const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001099 NULL,
1100""")
1101 for version in of_g.of_version_range:
1102 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1103 out.write("""
1104};
1105""")
1106