blob: ac4a9728d3f7c6fb6abc2bb431b315cfd7668e50 [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
Rich Lanea06d0c32013-03-25 08:52:03 -070042def gen_type_to_object_id(out, type_str, prefix, template,
43 value_array, max_val):
44 """
45 Generate C maps from various message class groups to object ids
46
47 For each version, create an array mapping the type info to the
48 object ID. Then define an array containing those pointers.
49 """
50
51 # Create unified arrays and get length
52 arr_len = type_maps.type_array_len(value_array, max_val)
53 all_ars = []
54 for version, val_dict in value_array.items(): # Per version dict
55 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
56 all_ars.append(ar)
57
58 len_name = "%s_ITEM_COUNT" % prefix
59
60 for i, ar in enumerate(all_ars):
61 version = i + 1
Rich Laneb157b0f2013-03-27 13:55:28 -070062 out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
Rich Lanea06d0c32013-03-25 08:52:03 -070063 (type_str, version, len_name))
64 for i in range(arr_len):
65 comma = ""
66 if i < arr_len - 1: # Avoid ultimate comma
67 comma = ","
68
69 # Per-version length check
70 if i < len(ar):
71 v = ar[i]
72 else:
73 v = type_maps.invalid_type
74
75 if v == type_maps.invalid_type:
76 out.write(" %-30s /* %d (Invalid) */\n" %
77 ("OF_OBJECT_INVALID" + comma, i))
78 else:
79 name = (template % v.upper()) + comma
80 out.write(" %-30s /* %d */\n" % (name, i))
81 out.write("};\n")
82
83 out.write("""
84/**
85 * Maps from %(c_name)s wire type values to LOCI object ids
86 *
87 * Indexed by wire version which is 1-based.
88 */
89
Rich Laneb157b0f2013-03-27 13:55:28 -070090const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -070091 NULL,
92""" % dict(name=type_str, c_name=prefix.lower()))
93 for version in of_g.of_version_range:
94 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
95 version=version))
96 out.write("""
97};
98
Andreas Wundsam53256162013-05-02 14:05:53 -070099""" % dict(name=type_str, u_name=type_str.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700100 max_val=max_val, c_name=prefix.lower()))
101
102def gen_type_maps(out):
103 """
104 Generate various type maps
105 @param out The file handle to write to
106 """
107
Rich Lanea06d0c32013-03-25 08:52:03 -0700108 # Generate maps from wire type values to object IDs
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700109 gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
110 "OF_%s_ERROR_MSG", type_maps.error_types,
111 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700112 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
113 "OF_ACTION_%s", type_maps.action_types,
114 max_type_value)
115 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
116 "OF_ACTION_ID_%s", type_maps.action_id_types,
117 max_type_value)
118 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700119 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700120 max_type_value)
121 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
122 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
123 max_type_value)
124 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
125 "OF_TABLE_FEATURE_PROP",
126 "OF_TABLE_FEATURE_PROP_%s",
127 type_maps.table_feature_prop_types,
128 max_type_value)
129 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
130 "OF_METER_BAND_%s", type_maps.meter_band_types,
131 max_type_value)
132 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
133 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
134 max_type_value)
Rich Lanee3113672013-12-06 17:09:57 -0800135 gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
136 "OF_GROUP_%s", type_maps.group_mod_types,
137 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700138
139 # FIXME: Multipart re-organization
140 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
141 "OF_%s_STATS_REQUEST", type_maps.stats_types,
142 max_type_value)
143 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
144 "OF_%s_STATS_REPLY", type_maps.stats_types,
145 max_type_value)
146 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
147 "OF_FLOW_%s", type_maps.flow_mod_types,
148 max_type_value)
149 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
150 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
151 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
152 "OF_%s", type_maps.message_types, max_type_value)
153
Rich Lane713d9282013-12-30 15:21:35 -0800154 gen_type_to_object_id(out, "bsn_tlv_type_to_id", "OF_BSN_TLV",
155 "OF_BSN_TLV_%s", type_maps.bsn_tlv_types,
156 max_type_value)
157
Rich Lanea06d0c32013-03-25 08:52:03 -0700158def gen_type_to_obj_map_functions(out):
159 """
Rich Lanec0e20ff2013-12-15 23:40:31 -0800160 Generate the templated type map functions
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 @param out The file handle to write to
162 """
163
164 ################################################################
165 # Generate all type-to-object-ID maps in a common way
166 ################################################################
167 map_template = """
168/**
169 * %(name)s wire type to object ID array.
170 * Treat as private; use function accessor below
171 */
172
Rich Laneb157b0f2013-03-27 13:55:28 -0700173extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700174
175#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
176
177/**
178 * Map an %(name)s wire value to an OF object
179 * @param %(name)s The %(name)s type wire value
180 * @param version The version associated with the check
181 * @return The %(name)s OF object type
182 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700183 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700184 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800185of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700186of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700187{
188 if (!OF_VERSION_OKAY(version)) {
189 return OF_OBJECT_INVALID;
190 }
191 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
192 return OF_OBJECT_INVALID;
193 }
194
195 return of_%(name)s_type_to_id[version][%(name)s];
196}
197"""
198 map_with_experimenter_template = """
199/**
200 * %(name)s wire type to object ID array.
201 * Treat as private; use function accessor below
202 */
203
Rich Laneb157b0f2013-03-27 13:55:28 -0700204extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700205
206#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
207
208/**
209 * Map an %(name)s wire value to an OF object
210 * @param %(name)s The %(name)s type wire value
211 * @param version The version associated with the check
212 * @return The %(name)s OF object type
213 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700214 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700215 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800216of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700217of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700218{
219 if (!OF_VERSION_OKAY(version)) {
220 return OF_OBJECT_INVALID;
221 }
222 if (%(name)s == OF_EXPERIMENTER_TYPE) {
223 return OF_%(u_name)s_EXPERIMENTER;
224 }
225 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
226 return OF_OBJECT_INVALID;
227 }
228
229 return of_%(name)s_type_to_id[version][%(name)s];
230}
231"""
Jonathan Stouta226fd72014-02-13 16:36:07 -0500232 table_features_prop_template = """
233/**
234 * %(name)s wire type to object ID array.
235 * Treat as private; use function accessor below
236 */
Rich Lanea06d0c32013-03-25 08:52:03 -0700237
Jonathan Stouta226fd72014-02-13 16:36:07 -0500238extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
239
240#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
241
242/**
243 * Map an %(name)s wire value to an OF object
244 * @param %(name)s The %(name)s type wire value
245 * @param version The version associated with the check
246 * @return The %(name)s OF object type
247 * @return OF_OBJECT_INVALID if type does not map to an object
248 *
249 */
250of_object_id_t
251of_%(name)s_to_object_id(int %(name)s, of_version_t version)
252{
253 if (!OF_VERSION_OKAY(version)) {
254 return OF_OBJECT_INVALID;
255 }
Jonathan Stouted300e02014-02-14 14:04:05 -0500256 if (%(name)s == 0xfffe) {
Jonathan Stouta226fd72014-02-13 16:36:07 -0500257 return OF_%(u_name)s_EXPERIMENTER;
258 }
Jonathan Stouted300e02014-02-14 14:04:05 -0500259 if (%(name)s == 0xffff) {
Jonathan Stout7a65c002014-02-13 17:27:28 -0500260 return OF_%(u_name)s_EXPERIMENTER_MISS;
261 }
Jonathan Stouta226fd72014-02-13 16:36:07 -0500262 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
263 return OF_OBJECT_INVALID;
264 }
265
266 return of_%(name)s_type_to_id[version][%(name)s];
267}
268"""
Rich Lanea06d0c32013-03-25 08:52:03 -0700269 stats_template = """
270/**
271 * %(name)s wire type to object ID array.
272 * Treat as private; use function accessor below
273 */
274
Rich Laneb157b0f2013-03-27 13:55:28 -0700275extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700276
277#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
278
279/**
280 * Map an %(name)s wire value to an OF object
281 * @param %(name)s The %(name)s type wire value
282 * @param version The version associated with the check
283 * @return The %(name)s OF object type
284 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700285 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700286 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800287of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700288of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700289{
290 if (!OF_VERSION_OKAY(version)) {
291 return OF_OBJECT_INVALID;
292 }
293 if (%(name)s == OF_EXPERIMENTER_TYPE) {
294 return OF_EXPERIMENTER_%(u_name)s;
295 }
296 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
297 return OF_OBJECT_INVALID;
298 }
299
300 return of_%(name)s_type_to_id[version][%(name)s];
301}
302"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700303
304 error_msg_template = """
305/**
306 * %(name)s wire type to object ID array.
307 * Treat as private; use function accessor below
308 */
309
310extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
311
312#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
313
314/**
315 * Map an %(name)s wire value to an OF object
316 * @param %(name)s The %(name)s type wire value
317 * @param version The version associated with the check
318 * @return The %(name)s OF object type
319 * @return OF_OBJECT_INVALID if type does not map to an object
320 *
321 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800322of_object_id_t
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700323of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
324{
325 if (!OF_VERSION_OKAY(version)) {
326 return OF_OBJECT_INVALID;
327 }
328 if (%(name)s == OF_EXPERIMENTER_TYPE) {
329 return OF_EXPERIMENTER_ERROR_MSG;
330 }
331 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
332 return OF_OBJECT_INVALID;
333 }
334
335 return of_%(name)s_type_to_id[version][%(name)s];
336}
337"""
338
Rich Lanea06d0c32013-03-25 08:52:03 -0700339 # Experimenter mapping functions
340 # Currently we support very few candidates, so we just do a
341 # list of if/elses
342 experimenter_function = """
343/**
344 * @brief Map a message known to be an exp msg to the proper object
345 *
346 * Assume that the message is a vendor/experimenter message. Determine
347 * the specific object type for the message.
348 * @param msg An OF message object (uint8_t *)
349 * @param length The number of bytes in the message (for error checking)
350 * @param version Version of message
351 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
352 *
353 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
354 */
355
Rich Lanec0e20ff2013-12-15 23:40:31 -0800356of_object_id_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700357of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
358 uint32_t experimenter_id;
359 uint32_t subtype;
360
361 /* Extract experimenter and subtype value; look for match from type maps */
362 experimenter_id = of_message_experimenter_id_get(msg);
363 subtype = of_message_experimenter_subtype_get(msg);
364
365 /* Do a simple if/else search for the ver, experimenter and subtype */
366"""
367 first = True
368 for version, experimenter_lists in type_maps.extension_message_subtype.items():
369 for exp, subtypes in experimenter_lists.items():
370 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700371 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700372 (version == %(ver_name)s)) {
373""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
374 for ext_msg, subtype in subtypes.items():
375 experimenter_function += """
376 if (subtype == %(subtype)s) {
377 return %(ext_msg)s;
378 }
379""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
380 experimenter_function += """
381 }
382"""
383 experimenter_function += """
384 return OF_EXPERIMENTER;
385}
386"""
387
388 # Message need different handling
389 msg_template = """
390/**
391 * %(name)s wire type to object ID array.
392 * Treat as private; use function accessor below
393 */
394
Rich Laneb157b0f2013-03-27 13:55:28 -0700395extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700396
397#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
398
399/**
400 * Extract the type info from the message and determine its object type
401 * @param msg An OF message object (uint8_t *)
402 * @param length The number of bytes in the message (for error checking)
403 * @returns object ID or OF_OBJECT_INVALID if parse error
404 */
405
Rich Lanec0e20ff2013-12-15 23:40:31 -0800406of_object_id_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700407of_message_to_object_id(of_message_t msg, int length) {
408 uint8_t type;
409 of_version_t ver;
410 of_object_id_t obj_id;
411 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700412 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700413 uint8_t flow_mod_cmd;
Rich Lane353a79f2013-11-13 10:39:56 -0800414 uint32_t experimenter, subtype;
Rich Lanee3113672013-12-06 17:09:57 -0800415 uint16_t group_mod_cmd;
Rich Lanea06d0c32013-03-25 08:52:03 -0700416
417 if (length < OF_MESSAGE_MIN_LENGTH) {
418 return OF_OBJECT_INVALID;
419 }
420 type = of_message_type_get(msg);
421 ver = of_message_version_get(msg);
422 if (!OF_VERSION_OKAY(ver)) {
423 return OF_OBJECT_INVALID;
424 }
425
426 if (type >= OF_MESSAGE_ITEM_COUNT) {
427 return OF_OBJECT_INVALID;
428 }
429
430 obj_id = of_message_type_to_id[ver][type];
431
432 /* Remap to specific message if known */
433 if (obj_id == OF_EXPERIMENTER) {
434 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
435 return OF_OBJECT_INVALID;
436 }
437 return of_message_experimenter_to_object_id(msg, ver);
438 }
439
440 /* Remap to add/delete/strict version */
441 if (obj_id == OF_FLOW_MOD) {
442 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
443 return OF_OBJECT_INVALID;
444 }
445 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
446 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
447 }
448
449 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
450 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
451 return OF_OBJECT_INVALID;
452 }
453 stats_type = of_message_stats_type_get(msg);
Rich Lane353a79f2013-11-13 10:39:56 -0800454 if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
455 if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
456 return OF_OBJECT_INVALID;
457 }
458 experimenter = of_message_stats_experimenter_id_get(msg);
459 subtype = of_message_stats_experimenter_subtype_get(msg);
460 if (obj_id == OF_STATS_REQUEST) {
461 obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
462 } else {
463 obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
464 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700465 } else {
Rich Lane353a79f2013-11-13 10:39:56 -0800466 if (obj_id == OF_STATS_REQUEST) {
467 obj_id = of_stats_request_to_object_id(stats_type, ver);
468 } else {
469 obj_id = of_stats_reply_to_object_id(stats_type, ver);
470 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700471 }
472 }
473
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700474 if (obj_id == OF_ERROR_MSG) {
475 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
476 return OF_OBJECT_INVALID;
477 }
478 err_type = of_message_error_type_get(msg);
479 obj_id = of_error_msg_to_object_id(err_type, ver);
480 }
481
Rich Lanee3113672013-12-06 17:09:57 -0800482 if (obj_id == OF_GROUP_MOD) {
483 if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
484 return OF_OBJECT_INVALID;
485 }
486 group_mod_cmd = of_message_group_mod_command_get(msg);
487 obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
488 }
489
Rich Lanea06d0c32013-03-25 08:52:03 -0700490 return obj_id;
491}
492"""
493
Rich Laned8d29c92013-09-24 13:46:42 -0700494 oxm_template = """
495/**
496 * oxm wire type to object ID array.
497 * Treat as private; use function accessor below
498 */
499
500extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
501
502#define OF_OXM_ITEM_COUNT %(ar_len)d\n
503
504/**
505 * Map an oxm wire value to an OF object
506 * @param oxm The oxm type wire value
507 * @param version The version associated with the check
508 * @return The oxm OF object type
509 * @return OF_OBJECT_INVALID if type does not map to an object
510 *
511 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800512of_object_id_t
Rich Laned8d29c92013-09-24 13:46:42 -0700513of_oxm_to_object_id(uint32_t type_len, of_version_t version)
514{
515 if (!OF_VERSION_OKAY(version)) {
516 return OF_OBJECT_INVALID;
517 }
518
519 uint16_t class = (type_len >> 16) & 0xffff;
520 uint8_t masked_type = (type_len >> 8) & 0xff;
521
522 if (class == 0x8000) {
523 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
524 return OF_OBJECT_INVALID;
525 }
526
527 return of_oxm_type_to_id[version][masked_type];
528 } else if (class == 0x0003) {
529 switch (masked_type) {
530 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
531 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
Rich Lane61718362013-10-24 16:59:42 -0700532 case 0x02: return OF_OXM_BSN_LAG_ID;
533 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laneeb21c4f2013-10-28 17:34:41 -0700534 case 0x04: return OF_OXM_BSN_VRF;
535 case 0x05: return OF_OXM_BSN_VRF_MASKED;
536 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
537 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
538 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
539 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
540 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
541 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
542 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
543 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700544 default: return OF_OBJECT_INVALID;
545 }
546 } else {
547 return OF_OBJECT_INVALID;
548 }
549}
550"""
551
Rich Lanea06d0c32013-03-25 08:52:03 -0700552 # Action types array gen
553 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700554 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700555 dict(name="action", u_name="ACTION", ar_len=ar_len))
556
557 # Action ID types array gen
558 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700559 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700560 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
561
562 # Instruction types array gen
563 ar_len = type_maps.type_array_len(type_maps.instruction_types,
564 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700565 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700566 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
567
568 # Queue prop types array gen
569 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
570 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700571 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700572 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
573
574 # Table feature prop types array gen
575 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
576 max_type_value)
Jonathan Stout9f17b4b2014-02-14 11:56:37 -0500577 out.write(table_features_prop_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700578 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
579 ar_len=ar_len))
580
581 # Meter band types array gen
582 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
583 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700584 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700585 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
586
587 # Hello elem types array gen
588 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
589 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700590 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700591 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
592
593 # Stats types array gen
594 ar_len = type_maps.type_array_len(type_maps.stats_types,
595 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700596 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700597 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700598 out.write(stats_template %
599 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700600 ar_len=ar_len))
601
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700602 ar_len = type_maps.type_array_len(type_maps.error_types,
603 max_type_value)
604 out.write(error_msg_template %
605 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
606# out.write(error_msg_function)
607
Rich Lanea06d0c32013-03-25 08:52:03 -0700608 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700609 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700610 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
611
Rich Lanee3113672013-12-06 17:09:57 -0800612 ar_len = type_maps.type_array_len(type_maps.group_mod_types,
613 max_type_value)
614 out.write(map_template %
615 dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
616
Rich Laned8d29c92013-09-24 13:46:42 -0700617 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700618 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
619 out.write("""
620/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
621""")
Rich Laned8d29c92013-09-24 13:46:42 -0700622 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700623
Rich Laned8d29c92013-09-24 13:46:42 -0700624 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700625 out.write(experimenter_function)
626 # Must follow stats reply/request
627 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700628 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700629 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
630
Rich Lane713d9282013-12-30 15:21:35 -0800631 # BSN TLV elem types array gen
632 ar_len = type_maps.type_array_len(type_maps.bsn_tlv_types,
633 max_type_value)
634 out.write(map_template %
635 dict(name="bsn_tlv", u_name="BSN_TLV", ar_len=ar_len))
636
Rich Lanea06d0c32013-03-25 08:52:03 -0700637def gen_type_data_header(out):
638
639 out.write("""
640/****************************************************************
641 *
642 * The following declarations are for type and length calculations.
643 * Implementations may be found in of_type_maps.c
644 *
645 ****************************************************************/
646/*
647 * Special case length functions for objects with
648 */
649""")
650 for ((cls, name), prev) in of_g.special_offsets.items():
651 s_cls = cls[3:] # take off of_
652 out.write("""
653/**
654 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700655 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700656 * length of %(name)s
657 * @param bytes[out] Where to store the calculated length
658 *
659 * Preceding data member is %(prev)s.
660 */
661extern int of_length_%(s_cls)s_%(name)s_get(
662 %(cls)s_t *obj, int *bytes);
663
664/**
665 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700666 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700667 * length of %(name)s
668 * @param offset[out] Where to store the calculated length
669 *
670 * Preceding data member is %(prev)s.
671 */
672extern int of_offset_%(s_cls)s_%(name)s_get(
673 %(cls)s_t *obj, int *offset);
674""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
675
676# NOT NEEDED YET
677# # For non-message, variable length objects, give a fun that
678# # calculates the length
679# for cls in of_g.standard_class_order:
680# s_cls = cls[3:] # take off of_
681# if !type_is_var_len(cls, version):
682# continue
683# out.write("""
684# /**
685# * Special length calculation for variable length object %(cls)s
686# * @param obj An object of type %(cls)s whose length is being calculated
687# * @param bytes[out] Where to store the calculated length
688# *
689# * The assumption is that the length member of the object is not
690# * valid and the length needs to be calculated from other information
691# * such as the parent.
692# */
693# extern int of_length_%(s_cls)s_get(
694# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -0700695# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -0700696
697 out.write("""
698/****************************************************************
699 * Wire type/length functions.
700 ****************************************************************/
701
702extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
703extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
704
705extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700706extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Rich Lanea06d0c32013-03-25 08:52:03 -0700707
708extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
709extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
710
Rich Lanea06d0c32013-03-25 08:52:03 -0700711/* Wire length is uint16 at front of structure */
712extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
713extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
714
715extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
716extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700717extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700718 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700719extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700720 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700721extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700722 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700723extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700724 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700725extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700726 of_object_id_t *id);
Rich Lane713d9282013-12-30 15:21:35 -0800727extern void of_bsn_tlv_wire_object_id_get(of_object_t *obj,
728 of_object_id_t *id);
Rich Lanea06d0c32013-03-25 08:52:03 -0700729
Rich Lane47085722013-07-12 16:27:04 -0700730#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -0700731#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -0700732 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -0700733
734extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
735extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
736
737extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
738 int *bytes);
739extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
740extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
741extern int of_extension_object_wire_push(of_object_t *obj);
742
743""")
744
745
746def gen_length_array(out):
747 """
748 Generate an array giving the lengths of all objects/versions
749 @param out The file handle to which to write
750 """
751 out.write("""
752/**
753 * An array with the number of bytes in the fixed length part
754 * of each OF object
755 */
756""")
757
758 for version in of_g.of_version_range:
759 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700760static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700761 -1, /* of_object is not instantiable */
762""" % version)
763 for i, cls in enumerate(of_g.all_class_order):
764 comma = ","
765 if i == len(of_g.all_class_order) - 1:
766 comma = ""
767 val = "-1" + comma
768 if (cls, version) in of_g.base_length:
769 val = str(of_g.base_length[(cls, version)]) + comma
770 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
771 out.write("};\n")
772
773 out.write("""
774/**
775 * Unified map of fixed length part of each object
776 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700777const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700778 NULL,
779""")
780 for version in of_g.of_version_range:
781 out.write(" of_object_fixed_len_v%d,\n" % version)
782 out.write("""
783};
784""")
785
Andreas Wundsam53256162013-05-02 14:05:53 -0700786
Rich Lanef70be942013-07-18 13:33:14 -0700787def gen_extra_length_array(out):
788 """
789 Generate an array giving the extra lengths of all objects/versions
790 @param out The file handle to which to write
791 """
792 out.write("""
793/**
794 * An array with the number of bytes in the extra length part
795 * of each OF object
796 */
797""")
798
799 for version in of_g.of_version_range:
800 out.write("""
801static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
802 -1, /* of_object is not instantiable */
803""" % version)
804 for i, cls in enumerate(of_g.all_class_order):
805 comma = ","
806 if i == len(of_g.all_class_order) - 1:
807 comma = ""
808 val = "-1" + comma
809 if (cls, version) in of_g.base_length:
810 val = str(of_g.extra_length.get((cls, version), 0)) + comma
811 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
812 out.write("};\n")
813
814 out.write("""
815/**
816 * Unified map of extra length part of each object
817 */
818const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
819 NULL,
820""")
821 for version in of_g.of_version_range:
822 out.write(" of_object_extra_len_v%d,\n" % version)
823 out.write("""
824};
825""")