blob: 2b469328643ba8de5878ea8631d4b95f53e19f68 [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)
Jonathan Stoutc26cbdb2014-03-04 12:46:17 -0500121 gen_type_to_object_id(out, "instruction_id_type_to_id", "OF_INSTRUCTION_ID",
Jonathan Stout83cedcc2014-03-03 16:38:00 -0500122 "OF_INSTRUCTION_ID_%s", type_maps.instruction_id_types,
123 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700124 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
125 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
126 max_type_value)
127 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
128 "OF_TABLE_FEATURE_PROP",
129 "OF_TABLE_FEATURE_PROP_%s",
130 type_maps.table_feature_prop_types,
131 max_type_value)
132 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
133 "OF_METER_BAND_%s", type_maps.meter_band_types,
134 max_type_value)
135 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
136 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
137 max_type_value)
Rich Lanee3113672013-12-06 17:09:57 -0800138 gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
139 "OF_GROUP_%s", type_maps.group_mod_types,
140 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700141
142 # FIXME: Multipart re-organization
143 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
144 "OF_%s_STATS_REQUEST", type_maps.stats_types,
145 max_type_value)
146 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
147 "OF_%s_STATS_REPLY", type_maps.stats_types,
148 max_type_value)
149 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
150 "OF_FLOW_%s", type_maps.flow_mod_types,
151 max_type_value)
152 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
153 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
154 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
155 "OF_%s", type_maps.message_types, max_type_value)
156
Rich Lane713d9282013-12-30 15:21:35 -0800157 gen_type_to_object_id(out, "bsn_tlv_type_to_id", "OF_BSN_TLV",
158 "OF_BSN_TLV_%s", type_maps.bsn_tlv_types,
159 max_type_value)
160
Rich Lanea06d0c32013-03-25 08:52:03 -0700161def gen_type_to_obj_map_functions(out):
162 """
Rich Lanec0e20ff2013-12-15 23:40:31 -0800163 Generate the templated type map functions
Rich Lanea06d0c32013-03-25 08:52:03 -0700164 @param out The file handle to write to
165 """
166
167 ################################################################
168 # Generate all type-to-object-ID maps in a common way
169 ################################################################
170 map_template = """
171/**
172 * %(name)s wire type to object ID array.
173 * Treat as private; use function accessor below
174 */
175
Rich Laneb157b0f2013-03-27 13:55:28 -0700176extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700177
178#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
179
180/**
181 * Map an %(name)s wire value to an OF object
182 * @param %(name)s The %(name)s type wire value
183 * @param version The version associated with the check
184 * @return The %(name)s OF object type
185 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700186 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700187 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800188of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700189of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700190{
191 if (!OF_VERSION_OKAY(version)) {
192 return OF_OBJECT_INVALID;
193 }
194 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
195 return OF_OBJECT_INVALID;
196 }
197
198 return of_%(name)s_type_to_id[version][%(name)s];
199}
200"""
201 map_with_experimenter_template = """
202/**
203 * %(name)s wire type to object ID array.
204 * Treat as private; use function accessor below
205 */
206
Rich Laneb157b0f2013-03-27 13:55:28 -0700207extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700208
209#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
210
211/**
212 * Map an %(name)s wire value to an OF object
213 * @param %(name)s The %(name)s type wire value
214 * @param version The version associated with the check
215 * @return The %(name)s OF object type
216 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700217 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700218 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800219of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700220of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700221{
222 if (!OF_VERSION_OKAY(version)) {
223 return OF_OBJECT_INVALID;
224 }
225 if (%(name)s == OF_EXPERIMENTER_TYPE) {
226 return OF_%(u_name)s_EXPERIMENTER;
227 }
228 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
229 return OF_OBJECT_INVALID;
230 }
231
232 return of_%(name)s_type_to_id[version][%(name)s];
233}
234"""
Jonathan Stouta226fd72014-02-13 16:36:07 -0500235 table_features_prop_template = """
236/**
237 * %(name)s wire type to object ID array.
238 * Treat as private; use function accessor below
239 */
Rich Lanea06d0c32013-03-25 08:52:03 -0700240
Jonathan Stouta226fd72014-02-13 16:36:07 -0500241extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
242
243#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
244
245/**
246 * Map an %(name)s wire value to an OF object
247 * @param %(name)s The %(name)s type wire value
248 * @param version The version associated with the check
249 * @return The %(name)s OF object type
250 * @return OF_OBJECT_INVALID if type does not map to an object
251 *
252 */
253of_object_id_t
254of_%(name)s_to_object_id(int %(name)s, of_version_t version)
255{
256 if (!OF_VERSION_OKAY(version)) {
257 return OF_OBJECT_INVALID;
258 }
Jonathan Stouted300e02014-02-14 14:04:05 -0500259 if (%(name)s == 0xfffe) {
Jonathan Stouta226fd72014-02-13 16:36:07 -0500260 return OF_%(u_name)s_EXPERIMENTER;
261 }
Jonathan Stouted300e02014-02-14 14:04:05 -0500262 if (%(name)s == 0xffff) {
Jonathan Stout7a65c002014-02-13 17:27:28 -0500263 return OF_%(u_name)s_EXPERIMENTER_MISS;
264 }
Jonathan Stouta226fd72014-02-13 16:36:07 -0500265 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
266 return OF_OBJECT_INVALID;
267 }
268
269 return of_%(name)s_type_to_id[version][%(name)s];
270}
271"""
Rich Lanea06d0c32013-03-25 08:52:03 -0700272 stats_template = """
273/**
274 * %(name)s wire type to object ID array.
275 * Treat as private; use function accessor below
276 */
277
Rich Laneb157b0f2013-03-27 13:55:28 -0700278extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700279
280#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
281
282/**
283 * Map an %(name)s wire value to an OF object
284 * @param %(name)s The %(name)s type wire value
285 * @param version The version associated with the check
286 * @return The %(name)s OF object type
287 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700288 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700289 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800290of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700291of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700292{
293 if (!OF_VERSION_OKAY(version)) {
294 return OF_OBJECT_INVALID;
295 }
296 if (%(name)s == OF_EXPERIMENTER_TYPE) {
297 return OF_EXPERIMENTER_%(u_name)s;
298 }
299 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
300 return OF_OBJECT_INVALID;
301 }
302
303 return of_%(name)s_type_to_id[version][%(name)s];
304}
305"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700306
307 error_msg_template = """
308/**
309 * %(name)s wire type to object ID array.
310 * Treat as private; use function accessor below
311 */
312
313extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
314
315#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
316
317/**
318 * Map an %(name)s wire value to an OF object
319 * @param %(name)s The %(name)s type wire value
320 * @param version The version associated with the check
321 * @return The %(name)s OF object type
322 * @return OF_OBJECT_INVALID if type does not map to an object
323 *
324 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800325of_object_id_t
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700326of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
327{
328 if (!OF_VERSION_OKAY(version)) {
329 return OF_OBJECT_INVALID;
330 }
331 if (%(name)s == OF_EXPERIMENTER_TYPE) {
332 return OF_EXPERIMENTER_ERROR_MSG;
333 }
334 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
335 return OF_OBJECT_INVALID;
336 }
337
338 return of_%(name)s_type_to_id[version][%(name)s];
339}
340"""
341
Rich Lanea06d0c32013-03-25 08:52:03 -0700342 # Experimenter mapping functions
343 # Currently we support very few candidates, so we just do a
344 # list of if/elses
345 experimenter_function = """
346/**
347 * @brief Map a message known to be an exp msg to the proper object
348 *
349 * Assume that the message is a vendor/experimenter message. Determine
350 * the specific object type for the message.
351 * @param msg An OF message object (uint8_t *)
352 * @param length The number of bytes in the message (for error checking)
353 * @param version Version of message
354 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
355 *
356 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
357 */
358
Rich Lanec0e20ff2013-12-15 23:40:31 -0800359of_object_id_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700360of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
361 uint32_t experimenter_id;
362 uint32_t subtype;
363
364 /* Extract experimenter and subtype value; look for match from type maps */
365 experimenter_id = of_message_experimenter_id_get(msg);
366 subtype = of_message_experimenter_subtype_get(msg);
367
368 /* Do a simple if/else search for the ver, experimenter and subtype */
369"""
370 first = True
371 for version, experimenter_lists in type_maps.extension_message_subtype.items():
372 for exp, subtypes in experimenter_lists.items():
373 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700374 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700375 (version == %(ver_name)s)) {
376""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
377 for ext_msg, subtype in subtypes.items():
378 experimenter_function += """
379 if (subtype == %(subtype)s) {
380 return %(ext_msg)s;
381 }
382""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
383 experimenter_function += """
384 }
385"""
386 experimenter_function += """
387 return OF_EXPERIMENTER;
388}
389"""
390
391 # Message need different handling
392 msg_template = """
393/**
394 * %(name)s wire type to object ID array.
395 * Treat as private; use function accessor below
396 */
397
Rich Laneb157b0f2013-03-27 13:55:28 -0700398extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700399
400#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
401
402/**
403 * Extract the type info from the message and determine its object type
404 * @param msg An OF message object (uint8_t *)
405 * @param length The number of bytes in the message (for error checking)
406 * @returns object ID or OF_OBJECT_INVALID if parse error
407 */
408
Rich Lanec0e20ff2013-12-15 23:40:31 -0800409of_object_id_t
Rich Lanea06d0c32013-03-25 08:52:03 -0700410of_message_to_object_id(of_message_t msg, int length) {
411 uint8_t type;
412 of_version_t ver;
413 of_object_id_t obj_id;
414 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700415 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700416 uint8_t flow_mod_cmd;
Rich Lane353a79f2013-11-13 10:39:56 -0800417 uint32_t experimenter, subtype;
Rich Lanee3113672013-12-06 17:09:57 -0800418 uint16_t group_mod_cmd;
Rich Lanea06d0c32013-03-25 08:52:03 -0700419
420 if (length < OF_MESSAGE_MIN_LENGTH) {
421 return OF_OBJECT_INVALID;
422 }
423 type = of_message_type_get(msg);
424 ver = of_message_version_get(msg);
425 if (!OF_VERSION_OKAY(ver)) {
426 return OF_OBJECT_INVALID;
427 }
428
429 if (type >= OF_MESSAGE_ITEM_COUNT) {
430 return OF_OBJECT_INVALID;
431 }
432
433 obj_id = of_message_type_to_id[ver][type];
434
435 /* Remap to specific message if known */
436 if (obj_id == OF_EXPERIMENTER) {
437 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
438 return OF_OBJECT_INVALID;
439 }
440 return of_message_experimenter_to_object_id(msg, ver);
441 }
442
443 /* Remap to add/delete/strict version */
444 if (obj_id == OF_FLOW_MOD) {
445 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
446 return OF_OBJECT_INVALID;
447 }
448 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
449 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
450 }
451
452 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
453 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
454 return OF_OBJECT_INVALID;
455 }
456 stats_type = of_message_stats_type_get(msg);
Rich Lane353a79f2013-11-13 10:39:56 -0800457 if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
458 if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
459 return OF_OBJECT_INVALID;
460 }
461 experimenter = of_message_stats_experimenter_id_get(msg);
462 subtype = of_message_stats_experimenter_subtype_get(msg);
463 if (obj_id == OF_STATS_REQUEST) {
464 obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
465 } else {
466 obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
467 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700468 } else {
Rich Lane353a79f2013-11-13 10:39:56 -0800469 if (obj_id == OF_STATS_REQUEST) {
470 obj_id = of_stats_request_to_object_id(stats_type, ver);
471 } else {
472 obj_id = of_stats_reply_to_object_id(stats_type, ver);
473 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700474 }
475 }
476
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700477 if (obj_id == OF_ERROR_MSG) {
478 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
479 return OF_OBJECT_INVALID;
480 }
481 err_type = of_message_error_type_get(msg);
482 obj_id = of_error_msg_to_object_id(err_type, ver);
483 }
484
Rich Lanee3113672013-12-06 17:09:57 -0800485 if (obj_id == OF_GROUP_MOD) {
486 if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
487 return OF_OBJECT_INVALID;
488 }
489 group_mod_cmd = of_message_group_mod_command_get(msg);
490 obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
491 }
492
Rich Lanea06d0c32013-03-25 08:52:03 -0700493 return obj_id;
494}
495"""
496
Rich Laned8d29c92013-09-24 13:46:42 -0700497 oxm_template = """
498/**
499 * oxm wire type to object ID array.
500 * Treat as private; use function accessor below
501 */
502
503extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
504
505#define OF_OXM_ITEM_COUNT %(ar_len)d\n
506
507/**
508 * Map an oxm wire value to an OF object
509 * @param oxm The oxm type wire value
510 * @param version The version associated with the check
511 * @return The oxm OF object type
512 * @return OF_OBJECT_INVALID if type does not map to an object
513 *
514 */
Rich Lanec0e20ff2013-12-15 23:40:31 -0800515of_object_id_t
Rich Laned8d29c92013-09-24 13:46:42 -0700516of_oxm_to_object_id(uint32_t type_len, of_version_t version)
517{
518 if (!OF_VERSION_OKAY(version)) {
519 return OF_OBJECT_INVALID;
520 }
521
522 uint16_t class = (type_len >> 16) & 0xffff;
523 uint8_t masked_type = (type_len >> 8) & 0xff;
524
525 if (class == 0x8000) {
526 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
527 return OF_OBJECT_INVALID;
528 }
529
530 return of_oxm_type_to_id[version][masked_type];
531 } else if (class == 0x0003) {
532 switch (masked_type) {
533 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
534 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
Rich Lane61718362013-10-24 16:59:42 -0700535 case 0x02: return OF_OXM_BSN_LAG_ID;
536 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laneeb21c4f2013-10-28 17:34:41 -0700537 case 0x04: return OF_OXM_BSN_VRF;
538 case 0x05: return OF_OXM_BSN_VRF_MASKED;
539 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
540 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
541 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
542 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
543 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
544 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
545 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
546 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Lane53ddf5c2014-03-20 15:24:08 -0700547 case 0x10: return OF_OXM_BSN_UDF0;
548 case 0x11: return OF_OXM_BSN_UDF0_MASKED;
549 case 0x12: return OF_OXM_BSN_UDF1;
550 case 0x13: return OF_OXM_BSN_UDF1_MASKED;
551 case 0x14: return OF_OXM_BSN_UDF2;
552 case 0x15: return OF_OXM_BSN_UDF2_MASKED;
553 case 0x16: return OF_OXM_BSN_UDF3;
554 case 0x17: return OF_OXM_BSN_UDF3_MASKED;
555 case 0x18: return OF_OXM_BSN_UDF4;
556 case 0x19: return OF_OXM_BSN_UDF4_MASKED;
557 case 0x1a: return OF_OXM_BSN_UDF5;
558 case 0x1b: return OF_OXM_BSN_UDF5_MASKED;
559 case 0x1c: return OF_OXM_BSN_UDF6;
560 case 0x1d: return OF_OXM_BSN_UDF6_MASKED;
561 case 0x1e: return OF_OXM_BSN_UDF7;
562 case 0x1f: return OF_OXM_BSN_UDF7_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700563 default: return OF_OBJECT_INVALID;
564 }
565 } else {
566 return OF_OBJECT_INVALID;
567 }
568}
569"""
570
Rich Lanea06d0c32013-03-25 08:52:03 -0700571 # Action types array gen
572 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700573 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700574 dict(name="action", u_name="ACTION", ar_len=ar_len))
575
576 # Action ID types array gen
577 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700578 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700579 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
580
581 # Instruction types array gen
582 ar_len = type_maps.type_array_len(type_maps.instruction_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="instruction", u_name="INSTRUCTION", ar_len=ar_len))
586
Jonathan Stout83cedcc2014-03-03 16:38:00 -0500587 # Instruction ID types array gen
588 ar_len = type_maps.type_array_len(type_maps.instruction_id_types, max_type_value)
589 out.write(map_with_experimenter_template %
590 dict(name="instruction_id", u_name="INSTRUCTION_ID", ar_len=ar_len))
591
Rich Lanea06d0c32013-03-25 08:52:03 -0700592 # Queue prop types array gen
593 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
594 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700595 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700596 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
597
598 # Table feature prop types array gen
599 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
600 max_type_value)
Jonathan Stout9f17b4b2014-02-14 11:56:37 -0500601 out.write(table_features_prop_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700602 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
603 ar_len=ar_len))
604
605 # Meter band types array gen
606 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
607 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700608 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700609 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
610
611 # Hello elem types array gen
612 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
613 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700614 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700615 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
616
617 # Stats types array gen
618 ar_len = type_maps.type_array_len(type_maps.stats_types,
619 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700620 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700621 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700622 out.write(stats_template %
623 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700624 ar_len=ar_len))
625
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700626 ar_len = type_maps.type_array_len(type_maps.error_types,
627 max_type_value)
628 out.write(error_msg_template %
629 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
630# out.write(error_msg_function)
631
Rich Lanea06d0c32013-03-25 08:52:03 -0700632 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700633 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700634 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
635
Rich Lanee3113672013-12-06 17:09:57 -0800636 ar_len = type_maps.type_array_len(type_maps.group_mod_types,
637 max_type_value)
638 out.write(map_template %
639 dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
640
Rich Laned8d29c92013-09-24 13:46:42 -0700641 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700642 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
643 out.write("""
644/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
645""")
Rich Laned8d29c92013-09-24 13:46:42 -0700646 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700647
Rich Laned8d29c92013-09-24 13:46:42 -0700648 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700649 out.write(experimenter_function)
650 # Must follow stats reply/request
651 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700652 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700653 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
654
Rich Lane713d9282013-12-30 15:21:35 -0800655 # BSN TLV elem types array gen
656 ar_len = type_maps.type_array_len(type_maps.bsn_tlv_types,
657 max_type_value)
658 out.write(map_template %
659 dict(name="bsn_tlv", u_name="BSN_TLV", ar_len=ar_len))
660
Rich Lanea06d0c32013-03-25 08:52:03 -0700661def gen_type_data_header(out):
662
663 out.write("""
664/****************************************************************
665 *
666 * The following declarations are for type and length calculations.
667 * Implementations may be found in of_type_maps.c
668 *
669 ****************************************************************/
670/*
671 * Special case length functions for objects with
672 */
673""")
674 for ((cls, name), prev) in of_g.special_offsets.items():
675 s_cls = cls[3:] # take off of_
676 out.write("""
677/**
678 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700679 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700680 * length of %(name)s
681 * @param bytes[out] Where to store the calculated length
682 *
683 * Preceding data member is %(prev)s.
684 */
685extern int of_length_%(s_cls)s_%(name)s_get(
686 %(cls)s_t *obj, int *bytes);
687
688/**
689 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700690 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700691 * length of %(name)s
692 * @param offset[out] Where to store the calculated length
693 *
694 * Preceding data member is %(prev)s.
695 */
696extern int of_offset_%(s_cls)s_%(name)s_get(
697 %(cls)s_t *obj, int *offset);
698""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
699
700# NOT NEEDED YET
701# # For non-message, variable length objects, give a fun that
702# # calculates the length
703# for cls in of_g.standard_class_order:
704# s_cls = cls[3:] # take off of_
705# if !type_is_var_len(cls, version):
706# continue
707# out.write("""
708# /**
709# * Special length calculation for variable length object %(cls)s
710# * @param obj An object of type %(cls)s whose length is being calculated
711# * @param bytes[out] Where to store the calculated length
712# *
713# * The assumption is that the length member of the object is not
714# * valid and the length needs to be calculated from other information
715# * such as the parent.
716# */
717# extern int of_length_%(s_cls)s_get(
718# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -0700719# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -0700720
721 out.write("""
722/****************************************************************
723 * Wire type/length functions.
724 ****************************************************************/
725
726extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
727extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
728
729extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700730
731extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
732extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
733
Rich Lanea06d0c32013-03-25 08:52:03 -0700734/* Wire length is uint16 at front of structure */
735extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
736extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
737
Rich Lane47085722013-07-12 16:27:04 -0700738#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -0700739#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -0700740 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -0700741
742extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
743extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
744
745extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
746 int *bytes);
747extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
748extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700749
750""")
751
752
753def gen_length_array(out):
754 """
755 Generate an array giving the lengths of all objects/versions
756 @param out The file handle to which to write
757 """
758 out.write("""
759/**
760 * An array with the number of bytes in the fixed length part
761 * of each OF object
762 */
763""")
764
765 for version in of_g.of_version_range:
766 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700767static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700768 -1, /* of_object is not instantiable */
769""" % version)
770 for i, cls in enumerate(of_g.all_class_order):
771 comma = ","
772 if i == len(of_g.all_class_order) - 1:
773 comma = ""
774 val = "-1" + comma
775 if (cls, version) in of_g.base_length:
776 val = str(of_g.base_length[(cls, version)]) + comma
777 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
778 out.write("};\n")
779
780 out.write("""
781/**
782 * Unified map of fixed length part of each object
783 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700784const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700785 NULL,
786""")
787 for version in of_g.of_version_range:
788 out.write(" of_object_fixed_len_v%d,\n" % version)
789 out.write("""
790};
791""")
792
Andreas Wundsam53256162013-05-02 14:05:53 -0700793
Rich Lanef70be942013-07-18 13:33:14 -0700794def gen_extra_length_array(out):
795 """
796 Generate an array giving the extra lengths of all objects/versions
797 @param out The file handle to which to write
798 """
799 out.write("""
800/**
801 * An array with the number of bytes in the extra length part
802 * of each OF object
803 */
804""")
805
806 for version in of_g.of_version_range:
807 out.write("""
808static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
809 -1, /* of_object is not instantiable */
810""" % version)
811 for i, cls in enumerate(of_g.all_class_order):
812 comma = ","
813 if i == len(of_g.all_class_order) - 1:
814 comma = ""
815 val = "-1" + comma
816 if (cls, version) in of_g.base_length:
817 val = str(of_g.extra_length.get((cls, version), 0)) + comma
818 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
819 out.write("};\n")
820
821 out.write("""
822/**
823 * Unified map of extra length part of each object
824 */
825const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
826 NULL,
827""")
828 for version in of_g.of_version_range:
829 out.write(" of_object_extra_len_v%d,\n" % version)
830 out.write("""
831};
832""")