blob: f1a427a460b6cb78cdbcd2ed87df3d1e93960c0b [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
108 out.write("#include <loci/loci.h>\n\n")
109
110 # Generate maps from wire type values to object IDs
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700111 gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
112 "OF_%s_ERROR_MSG", type_maps.error_types,
113 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700114 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
115 "OF_ACTION_%s", type_maps.action_types,
116 max_type_value)
117 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
118 "OF_ACTION_ID_%s", type_maps.action_id_types,
119 max_type_value)
120 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
Andreas Wundsam53256162013-05-02 14:05:53 -0700121 "OF_INSTRUCTION_%s", type_maps.instruction_types,
Rich Lanea06d0c32013-03-25 08:52:03 -0700122 max_type_value)
123 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
124 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
125 max_type_value)
126 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
127 "OF_TABLE_FEATURE_PROP",
128 "OF_TABLE_FEATURE_PROP_%s",
129 type_maps.table_feature_prop_types,
130 max_type_value)
131 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
132 "OF_METER_BAND_%s", type_maps.meter_band_types,
133 max_type_value)
134 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
135 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
136 max_type_value)
Rich Lanee3113672013-12-06 17:09:57 -0800137 gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
138 "OF_GROUP_%s", type_maps.group_mod_types,
139 max_type_value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700140
141 # FIXME: Multipart re-organization
142 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
143 "OF_%s_STATS_REQUEST", type_maps.stats_types,
144 max_type_value)
145 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
146 "OF_%s_STATS_REPLY", type_maps.stats_types,
147 max_type_value)
148 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
149 "OF_FLOW_%s", type_maps.flow_mod_types,
150 max_type_value)
151 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
152 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
153 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
154 "OF_%s", type_maps.message_types, max_type_value)
155
Rich Lanea06d0c32013-03-25 08:52:03 -0700156def gen_type_to_obj_map_functions(out):
157 """
158 Generate the templated static inline type map functions
159 @param out The file handle to write to
160 """
161
162 ################################################################
163 # Generate all type-to-object-ID maps in a common way
164 ################################################################
165 map_template = """
166/**
167 * %(name)s wire type to object ID array.
168 * Treat as private; use function accessor below
169 */
170
Rich Laneb157b0f2013-03-27 13:55:28 -0700171extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700172
173#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
174
175/**
176 * Map an %(name)s wire value to an OF object
177 * @param %(name)s The %(name)s type wire value
178 * @param version The version associated with the check
179 * @return The %(name)s OF object type
180 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700181 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700182 */
183static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700184of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700185{
186 if (!OF_VERSION_OKAY(version)) {
187 return OF_OBJECT_INVALID;
188 }
189 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
190 return OF_OBJECT_INVALID;
191 }
192
193 return of_%(name)s_type_to_id[version][%(name)s];
194}
195"""
196 map_with_experimenter_template = """
197/**
198 * %(name)s wire type to object ID array.
199 * Treat as private; use function accessor below
200 */
201
Rich Laneb157b0f2013-03-27 13:55:28 -0700202extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700203
204#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
205
206/**
207 * Map an %(name)s wire value to an OF object
208 * @param %(name)s The %(name)s type wire value
209 * @param version The version associated with the check
210 * @return The %(name)s OF object type
211 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700212 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700213 */
214static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700215of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700216{
217 if (!OF_VERSION_OKAY(version)) {
218 return OF_OBJECT_INVALID;
219 }
220 if (%(name)s == OF_EXPERIMENTER_TYPE) {
221 return OF_%(u_name)s_EXPERIMENTER;
222 }
223 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
224 return OF_OBJECT_INVALID;
225 }
226
227 return of_%(name)s_type_to_id[version][%(name)s];
228}
229"""
230
231 stats_template = """
232/**
233 * %(name)s wire type to object ID array.
234 * Treat as private; use function accessor below
235 */
236
Rich Laneb157b0f2013-03-27 13:55:28 -0700237extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700238
239#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
240
241/**
242 * Map an %(name)s wire value to an OF object
243 * @param %(name)s The %(name)s type wire value
244 * @param version The version associated with the check
245 * @return The %(name)s OF object type
246 * @return OF_OBJECT_INVALID if type does not map to an object
Andreas Wundsam53256162013-05-02 14:05:53 -0700247 *
Rich Lanea06d0c32013-03-25 08:52:03 -0700248 */
249static inline of_object_id_t
Andreas Wundsam53256162013-05-02 14:05:53 -0700250of_%(name)s_to_object_id(int %(name)s, of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700251{
252 if (!OF_VERSION_OKAY(version)) {
253 return OF_OBJECT_INVALID;
254 }
255 if (%(name)s == OF_EXPERIMENTER_TYPE) {
256 return OF_EXPERIMENTER_%(u_name)s;
257 }
258 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
259 return OF_OBJECT_INVALID;
260 }
261
262 return of_%(name)s_type_to_id[version][%(name)s];
263}
264"""
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700265
266 error_msg_template = """
267/**
268 * %(name)s wire type to object ID array.
269 * Treat as private; use function accessor below
270 */
271
272extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
273
274#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
275
276/**
277 * Map an %(name)s wire value to an OF object
278 * @param %(name)s The %(name)s type wire value
279 * @param version The version associated with the check
280 * @return The %(name)s OF object type
281 * @return OF_OBJECT_INVALID if type does not map to an object
282 *
283 */
284static inline of_object_id_t
285of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
286{
287 if (!OF_VERSION_OKAY(version)) {
288 return OF_OBJECT_INVALID;
289 }
290 if (%(name)s == OF_EXPERIMENTER_TYPE) {
291 return OF_EXPERIMENTER_ERROR_MSG;
292 }
293 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
294 return OF_OBJECT_INVALID;
295 }
296
297 return of_%(name)s_type_to_id[version][%(name)s];
298}
299"""
300
Rich Lanea06d0c32013-03-25 08:52:03 -0700301 # Experimenter mapping functions
302 # Currently we support very few candidates, so we just do a
303 # list of if/elses
304 experimenter_function = """
305/**
306 * @brief Map a message known to be an exp msg to the proper object
307 *
308 * Assume that the message is a vendor/experimenter message. Determine
309 * the specific object type for the message.
310 * @param msg An OF message object (uint8_t *)
311 * @param length The number of bytes in the message (for error checking)
312 * @param version Version of message
313 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
314 *
315 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
316 */
317
318static inline of_object_id_t
319of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
320 uint32_t experimenter_id;
321 uint32_t subtype;
322
323 /* Extract experimenter and subtype value; look for match from type maps */
324 experimenter_id = of_message_experimenter_id_get(msg);
325 subtype = of_message_experimenter_subtype_get(msg);
326
327 /* Do a simple if/else search for the ver, experimenter and subtype */
328"""
329 first = True
330 for version, experimenter_lists in type_maps.extension_message_subtype.items():
331 for exp, subtypes in experimenter_lists.items():
332 experimenter_function += """
Andreas Wundsam53256162013-05-02 14:05:53 -0700333 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
Rich Lanea06d0c32013-03-25 08:52:03 -0700334 (version == %(ver_name)s)) {
335""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
336 for ext_msg, subtype in subtypes.items():
337 experimenter_function += """
338 if (subtype == %(subtype)s) {
339 return %(ext_msg)s;
340 }
341""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
342 experimenter_function += """
343 }
344"""
345 experimenter_function += """
346 return OF_EXPERIMENTER;
347}
348"""
349
350 # Message need different handling
351 msg_template = """
352/**
353 * %(name)s wire type to object ID array.
354 * Treat as private; use function accessor below
355 */
356
Rich Laneb157b0f2013-03-27 13:55:28 -0700357extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700358
359#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
360
361/**
362 * Extract the type info from the message and determine its object type
363 * @param msg An OF message object (uint8_t *)
364 * @param length The number of bytes in the message (for error checking)
365 * @returns object ID or OF_OBJECT_INVALID if parse error
366 */
367
368static inline of_object_id_t
369of_message_to_object_id(of_message_t msg, int length) {
370 uint8_t type;
371 of_version_t ver;
372 of_object_id_t obj_id;
373 uint16_t stats_type;
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700374 uint16_t err_type;
Rich Lanea06d0c32013-03-25 08:52:03 -0700375 uint8_t flow_mod_cmd;
Rich Lane353a79f2013-11-13 10:39:56 -0800376 uint32_t experimenter, subtype;
Rich Lanee3113672013-12-06 17:09:57 -0800377 uint16_t group_mod_cmd;
Rich Lanea06d0c32013-03-25 08:52:03 -0700378
379 if (length < OF_MESSAGE_MIN_LENGTH) {
380 return OF_OBJECT_INVALID;
381 }
382 type = of_message_type_get(msg);
383 ver = of_message_version_get(msg);
384 if (!OF_VERSION_OKAY(ver)) {
385 return OF_OBJECT_INVALID;
386 }
387
388 if (type >= OF_MESSAGE_ITEM_COUNT) {
389 return OF_OBJECT_INVALID;
390 }
391
392 obj_id = of_message_type_to_id[ver][type];
393
394 /* Remap to specific message if known */
395 if (obj_id == OF_EXPERIMENTER) {
396 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
397 return OF_OBJECT_INVALID;
398 }
399 return of_message_experimenter_to_object_id(msg, ver);
400 }
401
402 /* Remap to add/delete/strict version */
403 if (obj_id == OF_FLOW_MOD) {
404 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
405 return OF_OBJECT_INVALID;
406 }
407 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
408 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
409 }
410
411 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
412 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
413 return OF_OBJECT_INVALID;
414 }
415 stats_type = of_message_stats_type_get(msg);
Rich Lane353a79f2013-11-13 10:39:56 -0800416 if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
417 if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
418 return OF_OBJECT_INVALID;
419 }
420 experimenter = of_message_stats_experimenter_id_get(msg);
421 subtype = of_message_stats_experimenter_subtype_get(msg);
422 if (obj_id == OF_STATS_REQUEST) {
423 obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
424 } else {
425 obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
426 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700427 } else {
Rich Lane353a79f2013-11-13 10:39:56 -0800428 if (obj_id == OF_STATS_REQUEST) {
429 obj_id = of_stats_request_to_object_id(stats_type, ver);
430 } else {
431 obj_id = of_stats_reply_to_object_id(stats_type, ver);
432 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700433 }
434 }
435
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700436 if (obj_id == OF_ERROR_MSG) {
437 if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
438 return OF_OBJECT_INVALID;
439 }
440 err_type = of_message_error_type_get(msg);
441 obj_id = of_error_msg_to_object_id(err_type, ver);
442 }
443
Rich Lanee3113672013-12-06 17:09:57 -0800444 if (obj_id == OF_GROUP_MOD) {
445 if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
446 return OF_OBJECT_INVALID;
447 }
448 group_mod_cmd = of_message_group_mod_command_get(msg);
449 obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
450 }
451
Rich Lanea06d0c32013-03-25 08:52:03 -0700452 return obj_id;
453}
454"""
455
Rich Laned8d29c92013-09-24 13:46:42 -0700456 oxm_template = """
457/**
458 * oxm wire type to object ID array.
459 * Treat as private; use function accessor below
460 */
461
462extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
463
464#define OF_OXM_ITEM_COUNT %(ar_len)d\n
465
466/**
467 * Map an oxm wire value to an OF object
468 * @param oxm The oxm type wire value
469 * @param version The version associated with the check
470 * @return The oxm OF object type
471 * @return OF_OBJECT_INVALID if type does not map to an object
472 *
473 */
474static inline of_object_id_t
475of_oxm_to_object_id(uint32_t type_len, of_version_t version)
476{
477 if (!OF_VERSION_OKAY(version)) {
478 return OF_OBJECT_INVALID;
479 }
480
481 uint16_t class = (type_len >> 16) & 0xffff;
482 uint8_t masked_type = (type_len >> 8) & 0xff;
483
484 if (class == 0x8000) {
485 if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
486 return OF_OBJECT_INVALID;
487 }
488
489 return of_oxm_type_to_id[version][masked_type];
490 } else if (class == 0x0003) {
491 switch (masked_type) {
492 case 0x00: return OF_OXM_BSN_IN_PORTS_128;
493 case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
Rich Lane61718362013-10-24 16:59:42 -0700494 case 0x02: return OF_OXM_BSN_LAG_ID;
495 case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
Rich Laneeb21c4f2013-10-28 17:34:41 -0700496 case 0x04: return OF_OXM_BSN_VRF;
497 case 0x05: return OF_OXM_BSN_VRF_MASKED;
498 case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
499 case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
500 case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
501 case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
502 case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
503 case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
504 case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
505 case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
Rich Laned8d29c92013-09-24 13:46:42 -0700506 default: return OF_OBJECT_INVALID;
507 }
508 } else {
509 return OF_OBJECT_INVALID;
510 }
511}
512"""
513
Rich Lanea06d0c32013-03-25 08:52:03 -0700514 # Action types array gen
515 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700516 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700517 dict(name="action", u_name="ACTION", ar_len=ar_len))
518
519 # Action ID types array gen
520 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700521 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700522 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
523
524 # Instruction types array gen
525 ar_len = type_maps.type_array_len(type_maps.instruction_types,
526 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700527 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700528 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
529
530 # Queue prop types array gen
531 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
532 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700533 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700534 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
535
536 # Table feature prop types array gen
537 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
538 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700539 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700540 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
541 ar_len=ar_len))
542
543 # Meter band types array gen
544 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
545 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700546 out.write(map_with_experimenter_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700547 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
548
549 # Hello elem types array gen
550 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
551 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700552 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700553 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
554
555 # Stats types array gen
556 ar_len = type_maps.type_array_len(type_maps.stats_types,
557 max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700558 out.write(stats_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700559 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
Andreas Wundsam53256162013-05-02 14:05:53 -0700560 out.write(stats_template %
561 dict(name="stats_request", u_name="STATS_REQUEST",
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 ar_len=ar_len))
563
Rob Vaterlausb3f49d92013-10-01 17:57:31 -0700564 ar_len = type_maps.type_array_len(type_maps.error_types,
565 max_type_value)
566 out.write(error_msg_template %
567 dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
568# out.write(error_msg_function)
569
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700571 out.write(map_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700572 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
573
Rich Lanee3113672013-12-06 17:09:57 -0800574 ar_len = type_maps.type_array_len(type_maps.group_mod_types,
575 max_type_value)
576 out.write(map_template %
577 dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
578
Rich Laned8d29c92013-09-24 13:46:42 -0700579 # OXM
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
581 out.write("""
582/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
583""")
Rich Laned8d29c92013-09-24 13:46:42 -0700584 out.write(oxm_template % dict(ar_len=ar_len))
Rich Lanea06d0c32013-03-25 08:52:03 -0700585
Rich Laned8d29c92013-09-24 13:46:42 -0700586 # Messages
Rich Lanea06d0c32013-03-25 08:52:03 -0700587 out.write(experimenter_function)
588 # Must follow stats reply/request
589 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
Andreas Wundsam53256162013-05-02 14:05:53 -0700590 out.write(msg_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700591 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
592
Rich Lanea06d0c32013-03-25 08:52:03 -0700593def gen_type_maps_header(out):
594 """
595 Generate various header file declarations for type maps
596 @param out The file handle to write to
597 """
598
599 out.write("""
600/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700601 * Generic experimenter type value. Applies to all except
Rich Lanea06d0c32013-03-25 08:52:03 -0700602 * top level message: Action, instruction, error, stats, queue_props, oxm
603 */
604#define OF_EXPERIMENTER_TYPE 0xffff
Rich Lane353a79f2013-11-13 10:39:56 -0800605
606int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
607int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
Rich Lanea06d0c32013-03-25 08:52:03 -0700608""")
609 gen_type_to_obj_map_functions(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700610
Rich Laneb157b0f2013-03-27 13:55:28 -0700611 out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanef70be942013-07-18 13:33:14 -0700612 out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
Rich Lanea06d0c32013-03-25 08:52:03 -0700613
614 out.write("""
615/**
616 * Map a message in a wire buffer object to its OF object id.
617 * @param wbuf Pointer to a wire buffer object, populated with an OF message
618 * @returns The object ID of the message
619 * @returns OF_OBJECT_INVALID if unable to parse the message type
620 */
621
622static inline of_object_id_t
623of_wire_object_id_get(of_wire_buffer_t *wbuf)
624{
625 of_message_t msg;
626
627 msg = (of_message_t)WBUF_BUF(wbuf);
628 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
629}
630
631/**
632 * Use the type/length from the wire buffer and init the object
633 * @param obj The object being initialized
634 * @param base_object_id If > 0, this indicates the base object
635 * @param max_len If > 0, the max length to expect for the obj
636 * type for inheritance checking
637 * @return OF_ERROR_
638 *
639 * Used for inheritance type objects such as actions and OXMs
640 * The type is checked and if valid, the object is initialized.
641 * Then the length is taken from the buffer.
642 *
643 * Note that the object version must already be properly set.
644 */
645static inline int
646of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
647 int max_len)
648{
649 if (obj->wire_type_get != NULL) {
650 of_object_id_t id;
651 obj->wire_type_get(obj, &id);
652 if (!of_wire_id_valid(id, base_object_id)) {
653 return OF_ERROR_PARSE;
654 }
655 obj->object_id = id;
656 /* Call the init function for this object type; do not push to wire */
657 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
658 }
659 if (obj->wire_length_get != NULL) {
660 int length;
661 obj->wire_length_get(obj, &length);
662 if (length < 0 || (max_len > 0 && length > max_len)) {
663 return OF_ERROR_PARSE;
664 }
665 obj->length = length;
666 } else {
667 /* @fixme Does this cover everything else? */
668 obj->length = of_object_fixed_len[obj->version][base_object_id];
669 }
670
671 return OF_ERROR_NONE;
672}
673
674""")
675
Rich Lanea06d0c32013-03-25 08:52:03 -0700676def gen_type_data_header(out):
677
678 out.write("""
679/****************************************************************
680 *
681 * The following declarations are for type and length calculations.
682 * Implementations may be found in of_type_maps.c
683 *
684 ****************************************************************/
685/*
686 * Special case length functions for objects with
687 */
688""")
689 for ((cls, name), prev) in of_g.special_offsets.items():
690 s_cls = cls[3:] # take off of_
691 out.write("""
692/**
693 * Special length calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700694 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700695 * length of %(name)s
696 * @param bytes[out] Where to store the calculated length
697 *
698 * Preceding data member is %(prev)s.
699 */
700extern int of_length_%(s_cls)s_%(name)s_get(
701 %(cls)s_t *obj, int *bytes);
702
703/**
704 * Special offset calculation for %(cls)s->%(name)s.
Andreas Wundsam53256162013-05-02 14:05:53 -0700705 * @param obj An object of type %(cls)s to check for
Rich Lanea06d0c32013-03-25 08:52:03 -0700706 * length of %(name)s
707 * @param offset[out] Where to store the calculated length
708 *
709 * Preceding data member is %(prev)s.
710 */
711extern int of_offset_%(s_cls)s_%(name)s_get(
712 %(cls)s_t *obj, int *offset);
713""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
714
715# NOT NEEDED YET
716# # For non-message, variable length objects, give a fun that
717# # calculates the length
718# for cls in of_g.standard_class_order:
719# s_cls = cls[3:] # take off of_
720# if !type_is_var_len(cls, version):
721# continue
722# out.write("""
723# /**
724# * Special length calculation for variable length object %(cls)s
725# * @param obj An object of type %(cls)s whose length is being calculated
726# * @param bytes[out] Where to store the calculated length
727# *
728# * The assumption is that the length member of the object is not
729# * valid and the length needs to be calculated from other information
730# * such as the parent.
731# */
732# extern int of_length_%(s_cls)s_get(
733# %(cls)s_t *obj, int *bytes);
Andreas Wundsam53256162013-05-02 14:05:53 -0700734# """ % dict(cls=cls, s_cls=s_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -0700735
736 out.write("""
737/****************************************************************
738 * Wire type/length functions.
739 ****************************************************************/
740
741extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
742extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
743
744extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700745extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Rich Lanea06d0c32013-03-25 08:52:03 -0700746
747extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
748extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
749
Rich Lanea06d0c32013-03-25 08:52:03 -0700750/* Wire length is uint16 at front of structure */
751extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
752extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
753
754extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
755extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700756extern void of_instruction_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700757 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700758extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700759 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700760extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700761 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700762extern void of_meter_band_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700763 of_object_id_t *id);
Andreas Wundsam53256162013-05-02 14:05:53 -0700764extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -0700765 of_object_id_t *id);
766
Rich Lane47085722013-07-12 16:27:04 -0700767#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
Rich Lanea06d0c32013-03-25 08:52:03 -0700768#define OF_OXM_LENGTH_SET(hdr, val) \\
Rich Lane47085722013-07-12 16:27:04 -0700769 (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
Rich Lanea06d0c32013-03-25 08:52:03 -0700770
771extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
772extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
773
774extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
775 int *bytes);
776extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
777extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
778extern int of_extension_object_wire_push(of_object_t *obj);
779
780""")
781
782
783def gen_length_array(out):
784 """
785 Generate an array giving the lengths of all objects/versions
786 @param out The file handle to which to write
787 """
788 out.write("""
789/**
790 * An array with the number of bytes in the fixed length part
791 * of each OF object
792 */
793""")
794
795 for version in of_g.of_version_range:
796 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -0700797static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700798 -1, /* of_object is not instantiable */
799""" % version)
800 for i, cls in enumerate(of_g.all_class_order):
801 comma = ","
802 if i == len(of_g.all_class_order) - 1:
803 comma = ""
804 val = "-1" + comma
805 if (cls, version) in of_g.base_length:
806 val = str(of_g.base_length[(cls, version)]) + comma
807 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
808 out.write("};\n")
809
810 out.write("""
811/**
812 * Unified map of fixed length part of each object
813 */
Rich Laneb157b0f2013-03-27 13:55:28 -0700814const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700815 NULL,
816""")
817 for version in of_g.of_version_range:
818 out.write(" of_object_fixed_len_v%d,\n" % version)
819 out.write("""
820};
821""")
822
Andreas Wundsam53256162013-05-02 14:05:53 -0700823
Rich Lanef70be942013-07-18 13:33:14 -0700824def gen_extra_length_array(out):
825 """
826 Generate an array giving the extra lengths of all objects/versions
827 @param out The file handle to which to write
828 """
829 out.write("""
830/**
831 * An array with the number of bytes in the extra length part
832 * of each OF object
833 */
834""")
835
836 for version in of_g.of_version_range:
837 out.write("""
838static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
839 -1, /* of_object is not instantiable */
840""" % version)
841 for i, cls in enumerate(of_g.all_class_order):
842 comma = ","
843 if i == len(of_g.all_class_order) - 1:
844 comma = ""
845 val = "-1" + comma
846 if (cls, version) in of_g.base_length:
847 val = str(of_g.extra_length.get((cls, version), 0)) + comma
848 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
849 out.write("};\n")
850
851 out.write("""
852/**
853 * Unified map of extra length part of each object
854 */
855const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
856 NULL,
857""")
858 for version in of_g.of_version_range:
859 out.write(" of_object_extra_len_v%d,\n" % version)
860 out.write("""
861};
862""")