blob: 924243af38657e57d351205f1eaf22248012930f [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28##
29# @brief C code generation for LOXI type related maps
30#
31
32import of_g
33import sys
34from generic_utils import *
35import loxi_front_end.oxm as oxm
36import loxi_front_end.type_maps as type_maps
37
38
39# Some number larger than small type values, but less then
40# reserved values like 0xffff
41max_type_value = 1000
42
43def gen_object_id_to_type(out):
44 out.write("""
45/**
46 * Map from object ID to primary wire type
47 *
48 * For messages, this is the header type; in particular for stats, this is
49 * the common stats request/response type. For per-stats types, use the
50 * stats type map. For things like actions, instructions or queue-props,
51 * this gives the "sub type".
52 */
53""")
54 for version in of_g.of_version_range:
55 out.write("static int\nof_object_to_type_map_v%d[OF_OBJECT_COUNT] = {\n"
56 %version)
57 out.write(" -1, /* of_object, not a valid specific type */\n")
58 for j, cls in enumerate(of_g.all_class_order):
59 comma = ""
60 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
61 comma = ","
62
63 if cls in type_maps.stats_reply_list:
64 out.write(" %d%s /* %s */\n" %
65 (type_maps.type_val[("of_stats_reply", version)],
66 comma, cls))
67 elif cls in type_maps.stats_request_list:
68 out.write(" %d%s /* %s */\n" %
69 (type_maps.type_val[("of_stats_request", version)],
70 comma, cls))
71 elif cls in type_maps.flow_mod_list:
72 out.write(" %d%s /* %s */\n" %
73 (type_maps.type_val[("of_flow_mod", version)],
74 comma, cls))
75 elif (cls, version) in type_maps.type_val:
76 out.write(" %d%s /* %s */\n" %
77 (type_maps.type_val[(cls, version)], comma, cls))
78 elif type_maps.message_is_extension(cls, version):
79 out.write(" %d%s /* %s */\n" %
80 (type_maps.type_val[("of_experimenter", version)],
81 comma, cls))
82 elif type_maps.action_is_extension(cls, version):
83 out.write(" %d%s /* %s */\n" %
84 (type_maps.type_val[("of_action_experimenter",
85 version)],
86 comma, cls))
87 elif type_maps.action_id_is_extension(cls, version):
88 out.write(" %d%s /* %s */\n" %
89 (type_maps.type_val[("of_action_id_experimenter",
90 version)],
91 comma, cls))
92 elif type_maps.instruction_is_extension(cls, version):
93 out.write(" %d%s /* %s */\n" %
94 (type_maps.type_val[("of_instruction_experimenter",
95 version)],
96 comma, cls))
97 elif type_maps.queue_prop_is_extension(cls, version):
98 out.write(" %d%s /* %s */\n" %
99 (type_maps.type_val[("of_queue_prop_experimenter",
100 version)],
101 comma, cls))
102 elif type_maps.table_feature_prop_is_extension(cls, version):
103 out.write(" %d%s /* %s */\n" %
104 (type_maps.type_val[("of_table_feature_prop_experimenter",
105 version)],
106 comma, cls))
107 else:
108 out.write(" -1%s /* %s (invalid) */\n" % (comma, cls))
109 out.write("};\n\n")
110
111 out.write("""
112/**
113 * Unified map, indexed by wire version which is 1-based.
114 */
115int *of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
116 NULL,
117""")
118 for version in of_g.of_version_range:
119 out.write(" of_object_to_type_map_v%d,\n" % version)
120 out.write("""
121};
122""")
123
124def gen_object_id_to_extension_data(out):
125 out.write("""
126/**
127 * Extension data.
128 * @fixme There must be a better way to represent this data
129 */
130""")
131 for version in of_g.of_version_range:
132 out.write("""
133static of_experimenter_data_t
134of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
135""" % version)
136 out.write(" {0, 0, 0}, /* of_object, not a valid specific type */\n")
137 for j, cls in enumerate(of_g.all_class_order):
138 comma = ""
139 if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
140 comma = ","
141
142 if type_maps.class_is_extension(cls, version):
143 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
144 subtype = type_maps.extension_to_subtype(cls, version)
145 out.write(" {1, %s, %d}%s /* %s */\n" %
146 (exp_name, subtype, comma, cls))
147 else:
148 out.write(" {0, 0, 0}%s /* %s (non-extension) */\n" %
149 (comma, cls))
150 out.write("};\n\n")
151
152 out.write("""
153/**
154 * Unified map, indexed by wire version which is 1-based.
155 */
156of_experimenter_data_t *of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
157 NULL,
158""")
159 for version in of_g.of_version_range:
160 out.write(" of_object_to_extension_data_v%d,\n" % version)
161 out.write("""
162};
163""")
164
165def gen_type_to_object_id(out, type_str, prefix, template,
166 value_array, max_val):
167 """
168 Generate C maps from various message class groups to object ids
169
170 For each version, create an array mapping the type info to the
171 object ID. Then define an array containing those pointers.
172 """
173
174 # Create unified arrays and get length
175 arr_len = type_maps.type_array_len(value_array, max_val)
176 all_ars = []
177 for version, val_dict in value_array.items(): # Per version dict
178 ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
179 all_ars.append(ar)
180
181 len_name = "%s_ITEM_COUNT" % prefix
182
183 for i, ar in enumerate(all_ars):
184 version = i + 1
185 out.write("static of_object_id_t\nof_%s_v%d[%s] = {\n" %
186 (type_str, version, len_name))
187 for i in range(arr_len):
188 comma = ""
189 if i < arr_len - 1: # Avoid ultimate comma
190 comma = ","
191
192 # Per-version length check
193 if i < len(ar):
194 v = ar[i]
195 else:
196 v = type_maps.invalid_type
197
198 if v == type_maps.invalid_type:
199 out.write(" %-30s /* %d (Invalid) */\n" %
200 ("OF_OBJECT_INVALID" + comma, i))
201 else:
202 name = (template % v.upper()) + comma
203 out.write(" %-30s /* %d */\n" % (name, i))
204 out.write("};\n")
205
206 out.write("""
207/**
208 * Maps from %(c_name)s wire type values to LOCI object ids
209 *
210 * Indexed by wire version which is 1-based.
211 */
212
213of_object_id_t *of_%(name)s[OF_VERSION_ARRAY_MAX] = {
214 NULL,
215""" % dict(name=type_str, c_name=prefix.lower()))
216 for version in of_g.of_version_range:
217 out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
218 version=version))
219 out.write("""
220};
221
222""" % dict(name=type_str, u_name=type_str.upper(),
223 max_val=max_val, c_name=prefix.lower()))
224
225def gen_type_maps(out):
226 """
227 Generate various type maps
228 @param out The file handle to write to
229 """
230
231 out.write("#include <loci/loci.h>\n\n")
232
233 # Generate maps from wire type values to object IDs
234 gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
235 "OF_ACTION_%s", type_maps.action_types,
236 max_type_value)
237 gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
238 "OF_ACTION_ID_%s", type_maps.action_id_types,
239 max_type_value)
240 gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
241 "OF_INSTRUCTION_%s", type_maps.instruction_types,
242 max_type_value)
243 gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
244 "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
245 max_type_value)
246 gen_type_to_object_id(out, "table_feature_prop_type_to_id",
247 "OF_TABLE_FEATURE_PROP",
248 "OF_TABLE_FEATURE_PROP_%s",
249 type_maps.table_feature_prop_types,
250 max_type_value)
251 gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
252 "OF_METER_BAND_%s", type_maps.meter_band_types,
253 max_type_value)
254 gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
255 "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
256 max_type_value)
257
258 # FIXME: Multipart re-organization
259 gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
260 "OF_%s_STATS_REQUEST", type_maps.stats_types,
261 max_type_value)
262 gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
263 "OF_%s_STATS_REPLY", type_maps.stats_types,
264 max_type_value)
265 gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
266 "OF_FLOW_%s", type_maps.flow_mod_types,
267 max_type_value)
268 gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
269 "OF_OXM_%s", type_maps.oxm_types, max_type_value)
270 gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
271 "OF_%s", type_maps.message_types, max_type_value)
272
273 gen_object_id_to_type(out)
274 gen_object_id_to_extension_data(out)
275 # Don't need array mapping ID to stats types right now; handled directly
276 # gen_object_id_to_stats_type(out)
277
278
279def gen_type_to_obj_map_functions(out):
280 """
281 Generate the templated static inline type map functions
282 @param out The file handle to write to
283 """
284
285 ################################################################
286 # Generate all type-to-object-ID maps in a common way
287 ################################################################
288 map_template = """
289/**
290 * %(name)s wire type to object ID array.
291 * Treat as private; use function accessor below
292 */
293
294extern of_object_id_t *of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
295
296#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
297
298/**
299 * Map an %(name)s wire value to an OF object
300 * @param %(name)s The %(name)s type wire value
301 * @param version The version associated with the check
302 * @return The %(name)s OF object type
303 * @return OF_OBJECT_INVALID if type does not map to an object
304 *
305 */
306static inline of_object_id_t
307of_%(name)s_to_object_id(int %(name)s, of_version_t version)
308{
309 if (!OF_VERSION_OKAY(version)) {
310 return OF_OBJECT_INVALID;
311 }
312 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
313 return OF_OBJECT_INVALID;
314 }
315
316 return of_%(name)s_type_to_id[version][%(name)s];
317}
318"""
319 map_with_experimenter_template = """
320/**
321 * %(name)s wire type to object ID array.
322 * Treat as private; use function accessor below
323 */
324
325extern of_object_id_t *of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
326
327#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
328
329/**
330 * Map an %(name)s wire value to an OF object
331 * @param %(name)s The %(name)s type wire value
332 * @param version The version associated with the check
333 * @return The %(name)s OF object type
334 * @return OF_OBJECT_INVALID if type does not map to an object
335 *
336 */
337static inline of_object_id_t
338of_%(name)s_to_object_id(int %(name)s, of_version_t version)
339{
340 if (!OF_VERSION_OKAY(version)) {
341 return OF_OBJECT_INVALID;
342 }
343 if (%(name)s == OF_EXPERIMENTER_TYPE) {
344 return OF_%(u_name)s_EXPERIMENTER;
345 }
346 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
347 return OF_OBJECT_INVALID;
348 }
349
350 return of_%(name)s_type_to_id[version][%(name)s];
351}
352"""
353
354 stats_template = """
355/**
356 * %(name)s wire type to object ID array.
357 * Treat as private; use function accessor below
358 */
359
360extern of_object_id_t *of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
361
362#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
363
364/**
365 * Map an %(name)s wire value to an OF object
366 * @param %(name)s The %(name)s type wire value
367 * @param version The version associated with the check
368 * @return The %(name)s OF object type
369 * @return OF_OBJECT_INVALID if type does not map to an object
370 *
371 */
372static inline of_object_id_t
373of_%(name)s_to_object_id(int %(name)s, of_version_t version)
374{
375 if (!OF_VERSION_OKAY(version)) {
376 return OF_OBJECT_INVALID;
377 }
378 if (%(name)s == OF_EXPERIMENTER_TYPE) {
379 return OF_EXPERIMENTER_%(u_name)s;
380 }
381 if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
382 return OF_OBJECT_INVALID;
383 }
384
385 return of_%(name)s_type_to_id[version][%(name)s];
386}
387"""
388 # Experimenter mapping functions
389 # Currently we support very few candidates, so we just do a
390 # list of if/elses
391 experimenter_function = """
392/**
393 * @brief Map a message known to be an exp msg to the proper object
394 *
395 * Assume that the message is a vendor/experimenter message. Determine
396 * the specific object type for the message.
397 * @param msg An OF message object (uint8_t *)
398 * @param length The number of bytes in the message (for error checking)
399 * @param version Version of message
400 * @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
401 *
402 * @todo put OF_EXPERIMENTER_<name> in loci_base.h
403 */
404
405static inline of_object_id_t
406of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
407 uint32_t experimenter_id;
408 uint32_t subtype;
409
410 /* Extract experimenter and subtype value; look for match from type maps */
411 experimenter_id = of_message_experimenter_id_get(msg);
412 subtype = of_message_experimenter_subtype_get(msg);
413
414 /* Do a simple if/else search for the ver, experimenter and subtype */
415"""
416 first = True
417 for version, experimenter_lists in type_maps.extension_message_subtype.items():
418 for exp, subtypes in experimenter_lists.items():
419 experimenter_function += """
420 if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
421 (version == %(ver_name)s)) {
422""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
423 for ext_msg, subtype in subtypes.items():
424 experimenter_function += """
425 if (subtype == %(subtype)s) {
426 return %(ext_msg)s;
427 }
428""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
429 experimenter_function += """
430 }
431"""
432 experimenter_function += """
433 return OF_EXPERIMENTER;
434}
435"""
436
437 # Message need different handling
438 msg_template = """
439/**
440 * %(name)s wire type to object ID array.
441 * Treat as private; use function accessor below
442 */
443
444extern of_object_id_t *of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
445
446#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
447
448/**
449 * Extract the type info from the message and determine its object type
450 * @param msg An OF message object (uint8_t *)
451 * @param length The number of bytes in the message (for error checking)
452 * @returns object ID or OF_OBJECT_INVALID if parse error
453 */
454
455static inline of_object_id_t
456of_message_to_object_id(of_message_t msg, int length) {
457 uint8_t type;
458 of_version_t ver;
459 of_object_id_t obj_id;
460 uint16_t stats_type;
461 uint8_t flow_mod_cmd;
462
463 if (length < OF_MESSAGE_MIN_LENGTH) {
464 return OF_OBJECT_INVALID;
465 }
466 type = of_message_type_get(msg);
467 ver = of_message_version_get(msg);
468 if (!OF_VERSION_OKAY(ver)) {
469 return OF_OBJECT_INVALID;
470 }
471
472 if (type >= OF_MESSAGE_ITEM_COUNT) {
473 return OF_OBJECT_INVALID;
474 }
475
476 obj_id = of_message_type_to_id[ver][type];
477
478 /* Remap to specific message if known */
479 if (obj_id == OF_EXPERIMENTER) {
480 if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
481 return OF_OBJECT_INVALID;
482 }
483 return of_message_experimenter_to_object_id(msg, ver);
484 }
485
486 /* Remap to add/delete/strict version */
487 if (obj_id == OF_FLOW_MOD) {
488 if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
489 return OF_OBJECT_INVALID;
490 }
491 flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
492 obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
493 }
494
495 if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
496 if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
497 return OF_OBJECT_INVALID;
498 }
499 stats_type = of_message_stats_type_get(msg);
500 if (obj_id == OF_STATS_REQUEST) {
501 obj_id = of_stats_request_to_object_id(stats_type, ver);
502 } else {
503 obj_id = of_stats_reply_to_object_id(stats_type, ver);
504 }
505 }
506
507 return obj_id;
508}
509"""
510
511 # Action types array gen
512 ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
513 out.write(map_with_experimenter_template %
514 dict(name="action", u_name="ACTION", ar_len=ar_len))
515
516 # Action ID types array gen
517 ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
518 out.write(map_with_experimenter_template %
519 dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
520
521 # Instruction types array gen
522 ar_len = type_maps.type_array_len(type_maps.instruction_types,
523 max_type_value)
524 out.write(map_with_experimenter_template %
525 dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
526
527 # Queue prop types array gen
528 ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
529 max_type_value)
530 out.write(map_with_experimenter_template %
531 dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
532
533 # Table feature prop types array gen
534 ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
535 max_type_value)
536 out.write(map_with_experimenter_template %
537 dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
538 ar_len=ar_len))
539
540 # Meter band types array gen
541 ar_len = type_maps.type_array_len(type_maps.meter_band_types,
542 max_type_value)
543 out.write(map_with_experimenter_template %
544 dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
545
546 # Hello elem types array gen
547 ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
548 max_type_value)
549 out.write(map_template %
550 dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
551
552 # Stats types array gen
553 ar_len = type_maps.type_array_len(type_maps.stats_types,
554 max_type_value)
555 out.write(stats_template %
556 dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
557 out.write(stats_template %
558 dict(name="stats_request", u_name="STATS_REQUEST",
559 ar_len=ar_len))
560
561 ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
562 out.write(map_template %
563 dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
564
565 ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
566 out.write("""
567/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
568""")
569 out.write(map_template %
570 dict(name="oxm", u_name="OXM", ar_len=ar_len))
571
572 out.write(experimenter_function)
573 # Must follow stats reply/request
574 ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
575 out.write(msg_template %
576 dict(name="message", u_name="MESSAGE", ar_len=ar_len))
577
578def gen_obj_to_type_map_functions(out):
579 """
580 Generate the static line maps from object IDs to types
581 @param out The file handle to write to
582 """
583
584 ################################################################
585 # Generate object ID to primary type map
586 ################################################################
587
588 out.write("""
589extern int *of_object_to_type_map[OF_VERSION_ARRAY_MAX];
590
591/**
592 * Map an object ID to its primary wire type value
593 * @param id An object ID
594 * @return For message objects, the type value in the OpenFlow header
595 * @return For non-message objects such as actions, instructions, OXMs
596 * returns the type value that appears in the respective sub-header
597 * @return -1 For improper version or out of bounds input
598 *
599 * NOTE that for stats request/reply, returns the header type, not the
600 * sub-type
601 *
602 * Also, note that the value is returned as a signed integer. So -1 is
603 * an error code, while 0xffff is the usual "experimenter" code.
604 */
605static inline int
606of_object_to_wire_type(of_object_id_t id, of_version_t version)
607{
608 if (!OF_VERSION_OKAY(version)) {
609 return -1;
610 }
611 if (id < 0 || id >= OF_OBJECT_COUNT) {
612 return -1;
613 }
614 return of_object_to_type_map[version][id];
615}
616
617""")
618
619 # Now for experimenter ids
620 out.write("""
621/**
622 * Map from object ID to a triple, (is_extension, experimenter id, subtype)
623 */
624""")
625 out.write("""
626typedef struct of_experimenter_data_s {
627 int is_extension; /* Boolean indication that this is an extension */
628 uint32_t experimenter_id;
629 uint32_t subtype;
630} of_experimenter_data_t;
631
632""")
633
634 out.write("""
635extern of_experimenter_data_t *of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
636
637/**
638 * Map from the object ID of an extension to the experimenter ID
639 */
640static inline uint32_t
641of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
642{
643 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
644 return (uint32_t) -1;
645 }
646 /* @fixme: Verify ver? */
647 return of_object_to_extension_data[ver][obj_id].experimenter_id;
648}
649
650/**
651 * Map from the object ID of an extension to the experimenter subtype
652 */
653static inline uint32_t
654of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
655{
656 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
657 return (uint32_t) -1;
658 }
659 /* @fixme: Verify ver? */
660 return of_object_to_extension_data[ver][obj_id].subtype;
661}
662
663/**
664 * Boolean function indicating the the given object ID/version
665 * is recognized as a supported (decode-able) extension.
666 */
667static inline int
668of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
669{
670 if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
671 return (uint32_t) -1;
672 }
673 /* @fixme: Verify ver? */
674 return of_object_to_extension_data[ver][obj_id].is_extension;
675}
676""")
677
678 ################################################################
679 # Generate object ID to the stats sub-type map
680 ################################################################
681
682 out.write("""
683/**
684 * Map an object ID to a stats type
685 * @param id An object ID
686 * @return The wire value for the stats type
687 * @return -1 if not supported for this version
688 * @return -1 if id is not a specific stats type ID
689 *
690 * Note that the value is returned as a signed integer. So -1 is
691 * an error code, while 0xffff is the usual "experimenter" code.
692 */
693
694static inline int
695of_object_to_stats_type(of_object_id_t id, of_version_t version)
696{
697 if (!OF_VERSION_OKAY(version)) {
698 return -1;
699 }
700 switch (id) {
701""")
702 # Assumes 1.2 contains all stats types and type values are
703 # the same across all versions
704 stats_names = dict()
705 for ver in of_g.of_version_range:
706 for name, value in type_maps.stats_types[ver].items():
707 if name in stats_names and (not value == stats_names[name]):
708 print "ERROR stats type differ violating assumption"
709 sys.exit(1)
710 stats_names[name] = value
711
712 for name, value in stats_names.items():
713 out.write(" case OF_%s_STATS_REPLY:\n" % name.upper())
714 out.write(" case OF_%s_STATS_REQUEST:\n" % name.upper())
715 for version in of_g.of_version_range:
716 if not name in type_maps.stats_types[version]:
717 out.write(" if (version == %s) break;\n" %
718 of_g.of_version_wire2name[version])
719 out.write(" return %d;\n" % value)
720 out.write("""
721 default:
722 break;
723 }
724 return -1; /* Not recognized as stats type object for this version */
725}
726""")
727
728 ################################################################
729 # Generate object ID to the flow mod sub-type map
730 ################################################################
731
732 out.write("""
733/**
734 * Map an object ID to a flow-mod command value
735 * @param id An object ID
736 * @return The wire value for the flow-mod command
737 * @return -1 if not supported for this version
738 * @return -1 if id is not a specific stats type ID
739 *
740 * Note that the value is returned as a signed integer. So -1 is
741 * an error code, while 0xffff is the usual "experimenter" code.
742 */
743
744static inline int
745of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
746{
747 if (!OF_VERSION_OKAY(version)) {
748 return -1;
749 }
750 switch (id) {
751""")
752 # Assumes 1.2 contains all stats types and type values are
753 # the same across all versions
754 flow_mod_names = dict()
755 for ver in of_g.of_version_range:
756 for name, value in type_maps.flow_mod_types[ver].items():
757 if name in flow_mod_names and \
758 (not value == flow_mod_names[name]):
759 print "ERROR flow mod command differ violating assumption"
760 sys.exit(1)
761 flow_mod_names[name] = value
762
763 for name, value in flow_mod_names.items():
764 out.write(" case OF_FLOW_%s:\n" % name.upper())
765 for version in of_g.of_version_range:
766 if not name in type_maps.flow_mod_types[version]:
767 out.write(" if (version == %s) break;\n" %
768 of_g.of_version_wire2name[version])
769 out.write(" return %d;\n" % value)
770 out.write("""
771 default:
772 break;
773 }
774 return -1; /* Not recognized as flow mod type object for this version */
775}
776
777""")
778
779def gen_type_maps_header(out):
780 """
781 Generate various header file declarations for type maps
782 @param out The file handle to write to
783 """
784
785 out.write("""
786/**
787 * Generic experimenter type value. Applies to all except
788 * top level message: Action, instruction, error, stats, queue_props, oxm
789 */
790#define OF_EXPERIMENTER_TYPE 0xffff
791""")
792 gen_type_to_obj_map_functions(out)
793 gen_obj_to_type_map_functions(out)
794
795 out.write("extern int *of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
796
797 out.write("""
798/**
799 * Map a message in a wire buffer object to its OF object id.
800 * @param wbuf Pointer to a wire buffer object, populated with an OF message
801 * @returns The object ID of the message
802 * @returns OF_OBJECT_INVALID if unable to parse the message type
803 */
804
805static inline of_object_id_t
806of_wire_object_id_get(of_wire_buffer_t *wbuf)
807{
808 of_message_t msg;
809
810 msg = (of_message_t)WBUF_BUF(wbuf);
811 return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
812}
813
814/**
815 * Use the type/length from the wire buffer and init the object
816 * @param obj The object being initialized
817 * @param base_object_id If > 0, this indicates the base object
818 * @param max_len If > 0, the max length to expect for the obj
819 * type for inheritance checking
820 * @return OF_ERROR_
821 *
822 * Used for inheritance type objects such as actions and OXMs
823 * The type is checked and if valid, the object is initialized.
824 * Then the length is taken from the buffer.
825 *
826 * Note that the object version must already be properly set.
827 */
828static inline int
829of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
830 int max_len)
831{
832 if (obj->wire_type_get != NULL) {
833 of_object_id_t id;
834 obj->wire_type_get(obj, &id);
835 if (!of_wire_id_valid(id, base_object_id)) {
836 return OF_ERROR_PARSE;
837 }
838 obj->object_id = id;
839 /* Call the init function for this object type; do not push to wire */
840 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
841 }
842 if (obj->wire_length_get != NULL) {
843 int length;
844 obj->wire_length_get(obj, &length);
845 if (length < 0 || (max_len > 0 && length > max_len)) {
846 return OF_ERROR_PARSE;
847 }
848 obj->length = length;
849 } else {
850 /* @fixme Does this cover everything else? */
851 obj->length = of_object_fixed_len[obj->version][base_object_id];
852 }
853
854 return OF_ERROR_NONE;
855}
856
857""")
858
859 # Generate the function that sets the object type fields
860 out.write("""
861
862/**
863 * Map a message in a wire buffer object to its OF object id.
864 * @param wbuf Pointer to a wire buffer object, populated with an OF message
865 * @returns The object ID of the message
866 * @returns OF_OBJECT_INVALID if unable to parse the message type
867 *
868 * Version must be set in the buffer prior to calling this routine
869 */
870
871static inline int
872of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
873{
874 int type;
875 of_version_t ver;
876 of_message_t msg;
877
878 msg = (of_message_t)WBUF_BUF(wbuf);
879
880 ver = of_message_version_get(msg);
881
882 /* ASSERT(id is a message object) */
883
884 if ((type = of_object_to_wire_type(id, ver)) < 0) {
885 return OF_ERROR_PARAM;
886 }
887 of_message_type_set(msg, type);
888
889 if ((type = of_object_to_stats_type(id, ver)) >= 0) {
890 /* It's a stats obj */
891 of_message_stats_type_set(msg, type);
892 }
893 if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
894 /* It's a flow mod obj */
895 of_message_flow_mod_command_set(msg, ver, type);
896 }
897 if (of_object_id_is_extension(id, ver)) {
898 uint32_t val32;
899
900 /* Set the experimenter and subtype codes */
901 val32 = of_extension_to_experimenter_id(id, ver);
902 of_message_experimenter_id_set(msg, val32);
903 val32 = of_extension_to_experimenter_subtype(id, ver);
904 of_message_experimenter_subtype_set(msg, val32);
905 }
906
907 return OF_ERROR_NONE;
908}
909""")
910
911def gen_type_data_header(out):
912
913 out.write("""
914/****************************************************************
915 *
916 * The following declarations are for type and length calculations.
917 * Implementations may be found in of_type_maps.c
918 *
919 ****************************************************************/
920/*
921 * Special case length functions for objects with
922 */
923""")
924 for ((cls, name), prev) in of_g.special_offsets.items():
925 s_cls = cls[3:] # take off of_
926 out.write("""
927/**
928 * Special length calculation for %(cls)s->%(name)s.
929 * @param obj An object of type %(cls)s to check for
930 * length of %(name)s
931 * @param bytes[out] Where to store the calculated length
932 *
933 * Preceding data member is %(prev)s.
934 */
935extern int of_length_%(s_cls)s_%(name)s_get(
936 %(cls)s_t *obj, int *bytes);
937
938/**
939 * Special offset calculation for %(cls)s->%(name)s.
940 * @param obj An object of type %(cls)s to check for
941 * length of %(name)s
942 * @param offset[out] Where to store the calculated length
943 *
944 * Preceding data member is %(prev)s.
945 */
946extern int of_offset_%(s_cls)s_%(name)s_get(
947 %(cls)s_t *obj, int *offset);
948""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
949
950# NOT NEEDED YET
951# # For non-message, variable length objects, give a fun that
952# # calculates the length
953# for cls in of_g.standard_class_order:
954# s_cls = cls[3:] # take off of_
955# if !type_is_var_len(cls, version):
956# continue
957# out.write("""
958# /**
959# * Special length calculation for variable length object %(cls)s
960# * @param obj An object of type %(cls)s whose length is being calculated
961# * @param bytes[out] Where to store the calculated length
962# *
963# * The assumption is that the length member of the object is not
964# * valid and the length needs to be calculated from other information
965# * such as the parent.
966# */
967# extern int of_length_%(s_cls)s_get(
968# %(cls)s_t *obj, int *bytes);
969# """ % dict(cls=cls, s_cls=s_cls))
970
971 out.write("""
972/****************************************************************
973 * Wire type/length functions.
974 ****************************************************************/
975
976extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
977extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
978
979extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
980extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
981extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
982extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
983
984extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
985extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
986
987extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
988
989/* Wire length is uint16 at front of structure */
990extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
991extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
992
993extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
994extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
995extern void of_instruction_wire_object_id_get(of_object_t *obj,
996 of_object_id_t *id);
997extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
998 of_object_id_t *id);
999extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
1000 of_object_id_t *id);
1001extern void of_meter_band_wire_object_id_get(of_object_t *obj,
1002 of_object_id_t *id);
1003extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
1004 of_object_id_t *id);
1005
1006/** @fixme VERIFY LENGTH IS NUMBER OF BYTES OF ENTRY INCLUDING HDR */
1007#define OF_OXM_MASKED_TYPE_GET(hdr) (((hdr) >> 8) & 0xff)
1008#define OF_OXM_MASKED_TYPE_SET(hdr, val) \\
1009 (hdr) = ((hdr) & 0xffff00ff) + (((val) & 0xff) << 8)
1010
1011#define OF_OXM_LENGTH_GET(hdr) ((hdr) & 0xff)
1012#define OF_OXM_LENGTH_SET(hdr, val) \\
1013 (hdr) = ((hdr) & 0xffffff00) + ((val) & 0xff)
1014
1015extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
1016extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
1017
1018extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
1019 int *bytes);
1020extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
1021extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
1022extern int of_extension_object_wire_push(of_object_t *obj);
1023
1024""")
1025
1026
1027def gen_length_array(out):
1028 """
1029 Generate an array giving the lengths of all objects/versions
1030 @param out The file handle to which to write
1031 """
1032 out.write("""
1033/**
1034 * An array with the number of bytes in the fixed length part
1035 * of each OF object
1036 */
1037""")
1038
1039 for version in of_g.of_version_range:
1040 out.write("""
1041static int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
1042 -1, /* of_object is not instantiable */
1043""" % version)
1044 for i, cls in enumerate(of_g.all_class_order):
1045 comma = ","
1046 if i == len(of_g.all_class_order) - 1:
1047 comma = ""
1048 val = "-1" + comma
1049 if (cls, version) in of_g.base_length:
1050 val = str(of_g.base_length[(cls, version)]) + comma
1051 out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
1052 out.write("};\n")
1053
1054 out.write("""
1055/**
1056 * Unified map of fixed length part of each object
1057 */
1058int *of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
1059 NULL,
1060""")
1061 for version in of_g.of_version_range:
1062 out.write(" of_object_fixed_len_v%d,\n" % version)
1063 out.write("""
1064};
1065""")
1066
1067
1068################################################################
1069################################################################
1070
1071# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
1072def gen_object_id_to_stats_type(out):
1073 out.write("""
1074/**
1075 * Map from message object ID to stats type
1076 *
1077 * All message object IDs are mapped for simplicity
1078 */
1079""")
1080 for version in of_g.of_version_range:
1081 out.write("int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
1082 out.write(" -1, /* of_object (invalid) */\n");
1083 for cls in of_g.ordered_messages:
1084 name = cls[3:]
1085 name = name[:name.find("_stats")]
1086 if (((cls in type_maps.stats_reply_list) or
1087 (cls in type_maps.stats_request_list)) and
1088 name in type_maps.stats_types[i]):
1089 out.write(" %d, /* %s */\n" %
1090 (type_maps.stats_types[i][name], cls))
1091 else:
1092 out.write(" -1, /* %s (invalid) */\n" % cls)
1093 out.write("};\n\n")
1094
1095 out.write("""
1096/**
1097 * Unified map, indexed by wire version which is 1-based.
1098 */
1099int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
1100 NULL,
1101""")
1102 for version in of_g.of_version_range:
1103 out.write(" of_object_to_stats_type_map_v%d,\n" % version)
1104 out.write("""
1105};
1106""")
1107