blob: 09c4f2f9faa8d4bdd13f4eb7f98ea62989b32620 [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@file code_gen.py
30Code generation functions for LOCI
31"""
32
33import sys
34import of_g
35import c_match
36from generic_utils import *
37import c_gen.c_type_maps as c_type_maps
38import loxi_front_end.type_maps as type_maps
39import loxi_front_end.flags as flags
40import loxi_utils.loxi_utils as loxi_utils
41import loxi_front_end.identifiers as identifiers
42
43# 'property' is for queues. Could be trouble
44
45
46################################################################
47#
48# Misc helper functions
49#
50################################################################
51
52def h_file_to_define(name):
53 """
54 Convert a .h file name to the define used for the header
55 """
56 h_name = name[:-2].upper()
57 h_name = "_" + h_name + "_H_"
58 return h_name
59
60def enum_name(cls):
61 """
62 Return the name used for an enum identifier for the given class
63 @param cls The class name
64 """
65 return loxi_utils.enum_name(cls)
66
67def member_returns_val(cls, m_name):
68 """
69 Should get accessor return a value rather than void
70 @param cls The class name
71 @param m_name The member name
72 @return True if of_g config and the specific member allow a
73 return value. Otherwise False
74 """
75 m_type = of_g.unified[cls]["union"][m_name]["m_type"]
76 return (config_check("get_returns") =="value" and
77 m_type in of_g.of_scalar_types)
78
79# TODO serialize match outside accessor?
80def accessor_return_type(a_type, m_type):
81 if loxi_utils.accessor_returns_error(a_type, m_type):
82 return "int WARN_UNUSED_RESULT"
83 else:
84 return "void"
85
86def accessor_return_success(a_type, m_type):
87 if loxi_utils.accessor_returns_error(a_type, m_type):
88 return "OF_ERROR_NONE"
89 else:
90 return ""
91
92################################################################
93#
94# Per-file generators, mapped to jump table below
95#
96################################################################
97
98def base_h_gen(out, name):
99 """
100 Generate code for base header file
101 @param out The file handle to write to
102 @param name The name of the file
103 """
104 common_top_matter(out, name)
105 base_h_content(out)
106 gen_object_enum(out)
107 out.write("""
108/****************************************************************
109 *
110 * Experimenter IDs
111 *
112 ****************************************************************/
113
114""")
115 for name, val in of_g.experimenter_name_to_id.items():
116 out.write("#define OF_EXPERIMENTER_ID_%s 0x%08x\n" %
117 (name.upper(), val))
118
119 out.write("""
120/****************************************************************
121 *
122 * OpenFlow Match version specific and generic defines
123 *
124 ****************************************************************/
125""")
126 c_match.gen_v4_match_compat(out)
127 c_match.gen_match_macros(out)
128 c_match.gen_oxm_defines(out)
129 out.write("\n#endif /* Base header file */\n")
130
131def identifiers_gen(out, filename):
132 """
133 Generate the macros for LOCI identifiers
134 @param out The file handle to write to
135 @param filename The name of the file
136 """
137 common_top_matter(out, filename)
138 out.write("""
139/**
140 * For each identifier from an OpenFlow header file, a Loxi version
141 * of the identifier is generated. For example, ofp_port_flood becomes
142 * OF_PORT_DEST_FLOOD. Loxi provides the following macros related to
143 * OpenFlow identifiers (using OF_IDENT_ as an example below):
144 * OF_IDENT_BY_VERSION(version) Get the value for the specific version
145 * OF_IDENT_SUPPORTED(version) Boolean: Is OF_IDENT defined for version
146 * OF_IDENT The common value across all versions if defined
147 * OF_IDENT_GENERIC A unique value across all OF identifiers
148 *
149 * For identifiers marked as flags, the following are also defined
150 * OF_IDENT_SET(flags, version)
151 * OF_IDENT_CLEAR(flags, version)
152 * OF_IDENT_TEST(flags, version)
153 *
154 * Notes:
155 *
156 * OF_IDENT_BY_VERSION(version) returns an undefined value
157 * if the passed version does not define OF_IDENT. It does not generate an
158 * error, nor record anything to the log file. If the value is the same
159 * across all defined versions, the version is ignored.
160 *
161 * OF_IDENT is only defined if the value is the same across all
162 * target LOXI versions FOR WHICH IT IS DEFINED. No error checking is
163 * done. This allows code to be written without requiring the version
164 * to be known or referenced when it doesn't matter. It does mean
165 * that when porting to a new version of OpenFlow, compile errors may
166 * occur. However, this is an indication that the existing code must
167 * be updated to account for a change in the semantics with the newly
168 * supported OpenFlow version.
169 *
170 * @fixme Currently we do not handle multi-bit flags or field values; for
171 * example, OF_TABLE_CONFIG_TABLE_MISS_CONTROLLER is the meaning for
172 * a zero value in the bits indicated by OF_TABLE_CONFIG_TABLE_MISS_MASK.
173 *
174 * @fixme Need to decide (or make a code gen option) on the requirement
175 * for defining OF_IDENT: Is it that all target versions define it and
176 * the agree? Or only that the versions which define it agree?
177 */
178""")
179
180 # Build value-by-version parameters and c_code
181 if len(of_g.target_version_list) > 1: # Supporting more than one version
182 vbv_params = []
183 vbv_code = ""
184 first = True
185 for version in of_g.target_version_list:
186 vbv_params.append("value_%s" % of_g.short_version_names[version])
187 if not first:
188 vbv_code += "\\\n "
189 else:
190 first = False
191 last_value = "value_%s" % of_g.short_version_names[version]
192 vbv_code += "((version) == %s) ? (%s) : " % \
193 (of_g.of_version_wire2name[version], last_value)
194 # @todo Using last value, can optimize out last ?
195 vbv_code += "(%s)" % last_value
196
197 out.write("""
198/**
199 * @brief True for the special case of all versions supported
200 */
201#define OF_IDENT_IN_ALL_VERSIONS 1 /* Indicates identifier in all versions */
202
203/**
204 * @brief General macro to map version to value where values given as params
205 *
206 * If unknown version is passed, use the latest version's value
207 */
208#define OF_VALUE_BY_VERSION(version, %s) \\
209 (%s)
210
211/**
212 * @brief Generic set a flag
213 */
214#define OF_FLAG_SET(flags, mask) (flags) = (flags) | (mask)
215
216/**
217 * @brief Generic test if a flag is set
218 */
219#define OF_FLAG_CLEAR(flags, mask) (flags) = (flags) & ~(mask)
220
221/**
222 * @brief Generic test if a flag is set
223 */
224#define OF_FLAG_TEST(flags, mask) ((flags) & (mask) ? 1 : 0)
225
226/**
227 * @brief Set a flag where the value is an enum indication of bit shift
228 */
229#define OF_FLAG_ENUM_SET(flags, e_val) OF_FLAG_SET(flags, 1 << (e_val))
230
231/**
232 * @brief Clear a flag where the value is an enum indication of bit shift
233 */
234#define OF_FLAG_ENUM_CLEAR(flags, e_val) OF_FLAG_CLEAR(flags, 1 << (e_val))
235
236/**
237 * @brief Test a flag where the value is an enum indication of bit shift
238 */
239#define OF_FLAG_ENUM_TEST(flags, e_val) OF_FLAG_TEST(flags, 1 << (e_val))
240""" % (", ".join(vbv_params), vbv_code))
241
242 # For each group of identifiers, bunch ident defns
243 count = 1
244 keys = of_g.identifiers_by_group.keys()
245 keys.sort()
246 for group in keys:
247 idents = of_g.identifiers_by_group[group]
248 idents.sort()
249 out.write("""
250/****************************************************************
251 * Identifiers from %s
252 *****************************************************************/
253""" % group)
254 for ident in idents:
255 info = of_g.identifiers[ident]
256
257 keys = info["values_by_version"].keys()
258 keys.sort()
259
260 out.write("""
261/*
262 * Defines for %(ident)s
263 * Original name %(ofp_name)s
264 */
265""" % dict(ident=ident, ofp_name=info["ofp_name"]))
266
267 # Generate supported versions macro
268 if len(keys) == len(of_g.target_version_list): # Defined for all
269 out.write("""\
270#define %(ident)s_SUPPORTED(version) OF_IDENT_IN_ALL_VERSIONS
271""" % dict(ident=ident))
272 else: # Undefined for some version
273 sup_list = []
274 for version in keys:
275 sup_list.append("((version) == %s)" %
276 of_g.of_version_wire2name[version])
277 out.write("""\
278#define %(ident)s_SUPPORTED(version) \\
279 (%(sup_str)s)
280""" % dict(ident=ident, sup_str=" || \\\n ".join(sup_list)))
281
282 # Generate value macro
283 if identifiers.defined_versions_agree(of_g.identifiers,
284 of_g.target_version_list,
285 ident):
286 out.write("""\
287#define %(ident)s (%(value)s)
288#define %(ident)s_BY_VERSION(version) (%(value)s)
289""" % dict(ident=ident,value=info["common_value"]))
290 else: # Values differ between versions
291 # Generate version check and value by version
292 val_list = []
293 # Order of params matters
294 for version in of_g.target_version_list:
295 if version in info["values_by_version"]:
296 value = info["values_by_version"][version]
297 else:
298 value = identifiers.UNDEFINED_IDENT_VALUE
299 val_list.append("%s" % value)
300 out.write("""\
301#define %(ident)s_BY_VERSION(version) \\
302 OF_VALUE_BY_VERSION(version, %(val_str)s)
303""" % dict(ident=ident, val_str=", ".join(val_list)))
304 if flags.ident_is_flag(ident):
305 log("Treating %s as a flag" % ident)
306 out.write("""
307#define %(ident)s_SET(flags, version) \\
308 OF_FLAG_SET(flags, %(ident)s_BY_VERSION(version))
309#define %(ident)s_TEST(flags, version) \\
310 OF_FLAG_TEST(flags, %(ident)s_BY_VERSION(version))
311#define %(ident)s_CLEAR(flags, version) \\
312 OF_FLAG_CLEAR(flags, %(ident)s_BY_VERSION(version))
313""" % dict(ident=ident))
314
315 out.write("#define %(ident)s_GENERIC %(count)d\n"
316 % dict(ident=ident, count=count))
317 count += 1 # This count should probably be promoted higher
318
319 log("Generated %d identifiers" % (count - 1))
320 out.write("\n#endif /* Loci identifiers header file */\n")
321
322def base_h_external(out, filename):
323 """
324 Copy contents of external file to base header
325
326 The contents of the filename are copied literally into the
327 out file handler. This allows openflow common defines to
328 be entered into the LoxiGen code base. The content of this
329 code must depend only on standard C headers.
330 """
331 infile = open(filename, "r")
332 contents = infile.read()
333 out.write(contents)
334 infile.close()
335
336def match_h_gen(out, name):
337 """
338 Generate code for
339 @param out The file handle to write to
340 @param name The name of the file
341 """
342 c_match.match_h_top_matter(out, name)
343 c_match.gen_incompat_members(out)
344 c_match.gen_match_struct(out)
345 c_match.gen_match_comp(out)
346# c_match.gen_match_accessors(out)
347 out.write("\n#endif /* Match header file */\n")
348
349def top_h_gen(out, name):
350 """
351 Generate code for
352 @param out The file handle to write to
353 @param name The name of the file
354 """
355 external_h_top_matter(out, name)
356 out.write("""
357
358typedef enum loci_log_level {
359 LOCI_LOG_LEVEL_TRACE,
360 LOCI_LOG_LEVEL_VERBOSE,
361 LOCI_LOG_LEVEL_INFO,
362 LOCI_LOG_LEVEL_WARN,
363 LOCI_LOG_LEVEL_ERROR,
364 LOCI_LOG_LEVEL_MSG
365} loci_log_level_t;
366
367/**
368 * @brief Output a log message.
369 * @param level The log level.
370 * @param fname The function name.
371 * @param file The file name.
372 * @param line The line number.
373 * @param format The message format string.
374 */
375typedef int (*loci_logger_f)(loci_log_level_t level,
376 const char *fname, const char *file, int line,
377 const char *format, ...);
378
379/*
380 * This variable should be set by the user of the library to redirect logs to
381 * their log infrastructure. The default drops all logs.
382 */
383extern loci_logger_f loci_logger;
384
385/**
386 * Map a generic object to the underlying wire buffer
387 *
388 * Treat as private
389 */
390#define OF_OBJECT_TO_MESSAGE(obj) \\
391 ((of_message_t)(WBUF_BUF((obj)->wire_object.wbuf)))
392
393/**
394 * Macro for the fixed length part of an object
395 *
396 * @param obj The object whose extended length is being calculated
397 * @returns length in bytes of non-variable part of the object
398 */
399#define OF_OBJECT_FIXED_LENGTH(obj) \\
400 (of_object_fixed_len[(obj)->version][(obj)->object_id])
401
402/**
403 * Return the length of the object beyond its fixed length
404 *
405 * @param obj The object whose extended length is being calculated
406 * @returns length in bytes of non-variable part of the object
407 *
408 * Most variable length fields are alone at the end of a structure.
409 * Their length is a simple calculation, just the total length of
410 * the parent minus the length of the non-variable part of the
411 * parent's class type.
412 */
413
414#define OF_OBJECT_VARIABLE_LENGTH(obj) \\
415 ((obj)->length - OF_OBJECT_FIXED_LENGTH(obj))
416
417/* FIXME: Where do these go? */
418/* Low level maps btwn wire version + type and object ids */
419extern int of_message_is_stats_request(int type, int w_ver);
420extern int of_message_is_stats_reply(int type, int w_ver);
421extern int of_message_stats_reply_to_object_id(int stats_type, int w_ver);
422extern int of_message_stats_request_to_object_id(int stats_type, int w_ver);
423extern int of_message_type_to_object_id(int type, int w_ver);
424
425extern int of_wire_buffer_of_match_get(of_object_t *obj, int offset,
426 of_match_t *match);
427extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
428 of_match_t *match, int cur_len);
429extern void of_extension_object_id_set(of_object_t *obj, of_object_id_t id);
430""")
431
432 # gen_base_types(out)
433
434 gen_struct_typedefs(out)
435 gen_acc_pointer_typedefs(out)
436 gen_new_function_declarations(out)
437 if config_check("gen_unified_fns"):
438 gen_accessor_declarations(out)
439
440 gen_common_struct_definitions(out)
441 gen_flow_add_setup_function_declarations(out)
442 if config_check("gen_fn_ptrs"): # Otherwise, all classes are from generic cls
443 gen_struct_definitions(out)
444 gen_generic_union(out)
445 gen_generics(out)
446 gen_top_static_functions(out)
447 out.write("""
448/****************************************************************
449 *
450 * Declarations of maps between on-the-wire type values and LOCI identifiers
451 *
452 ****************************************************************/
453""")
454 c_type_maps.gen_type_maps_header(out)
455 c_type_maps.gen_type_data_header(out)
456 c_match.gen_declarations(out)
457 # @fixme Move debug stuff to own fn
458 out.write("""
459/**
460 * Macro to check consistency of length for top level objects
461 *
462 * If the object has no parent then its length should match the
463 * underlying wire buffer's current bytes.
464 */
465#define OF_LENGTH_CHECK_ASSERT(obj) \\
466 ASSERT(((obj)->parent != NULL) || \\
467 ((obj)->wire_object.wbuf == NULL) || \\
468 (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
469
470#define OF_DEBUG_DUMP
471#if defined(OF_DEBUG_DUMP)
472extern void dump_match(of_match_t *match);
473#endif /* OF_DEBUG_DUMP */
474""")
475
476 out.write("\n#endif /* Top header file */\n")
477
478def match_c_gen(out, name):
479 """
480 Generate code for
481 @param out The file handle to write to
482 @param name The name of the file
483 """
484 c_match.match_c_top_matter(out, name)
485 c_match.gen_match_conversions(out)
486 c_match.gen_serialize(out)
487 c_match.gen_deserialize(out)
488
489def gen_len_offset_macros(out):
490 """
491 Special case length and offset calculations put directly into
492 loci.c as they are private.
493 """
494
495 out.write("""
496/****************************************************************
497 * Special case macros for calculating variable lengths and offsets
498 ****************************************************************/
499
500/**
501 * Get a u16 directly from an offset in an object's wire buffer
502 * @param obj An of_object_t object
503 * @param offset Base offset of the uint16 relative to the object
504 *
505 */
506
507static inline int
508of_object_u16_get(of_object_t *obj, int offset) {
509 uint16_t val16;
510
511 of_wire_buffer_u16_get(obj->wire_object.wbuf,
512 obj->wire_object.obj_offset + offset, &val16);
513
514 return (int)val16;
515}
516
517/**
518 * Set a u16 directly at an offset in an object's wire buffer
519 * @param obj An of_object_t object
520 * @param offset Base offset of the uint16 relative to the object
521 * @param val The value to store
522 *
523 */
524
525static inline void
526of_object_u16_set(of_object_t *obj, int offset, int value) {
527 uint16_t val16;
528
529 val16 = (uint16_t)value;
530 of_wire_buffer_u16_set(obj->wire_object.wbuf,
531 obj->wire_object.obj_offset + offset, val16);
532}
533
534/**
535 * Get length of an object with a TLV header with uint16_t
536 * @param obj An object with a match member
537 * @param offset The wire offset of the start of the object
538 *
539 * The length field follows the type field.
540 */
541
542#define _TLV16_LEN(obj, offset) \\
543 (of_object_u16_get((of_object_t *)(obj), (offset) + 2))
544
545/**
546 * Get length of an object that is the "rest" of the object
547 * @param obj An object with a match member
548 * @param offset The wire offset of the start of the object
549 *
550 */
551
552#define _END_LEN(obj, offset) ((obj)->length - (offset))
553
554/**
555 * Get length of the action list object in a packet_out object
556 * @param obj An object of type of_packet_out
557 *
558 * The length field is just before the end of the fixed length
559 * part of the object in all versions.
560 */
561
562#define _PACKET_OUT_ACTION_LEN(obj) \\
563 (of_object_u16_get((of_object_t *)(obj), \\
564 of_object_fixed_len[(obj)->version][OF_PACKET_OUT] - 2))
565
566/**
567 * Set length of the action list object in a packet_out object
568 * @param obj An object of type of_packet_out
569 *
570 * The length field is just before the end of the fixed length
571 * part of the object in all versions.
572 */
573
574#define _PACKET_OUT_ACTION_LEN_SET(obj, len) \\
575 (of_object_u16_set((of_object_t *)(obj), \\
576 of_object_fixed_len[(obj)->version][OF_PACKET_OUT] - 2, len))
577
578/*
579 * Match structs in 1.2 come at the end of the fixed length part
580 * of structures. They add 8 bytes to the minimal length of the
581 * message, but are also variable length. This means that the
582 * type/length offsets are 8 bytes back from the end of the fixed
583 * length part of the object. The right way to handle this is to
584 * expose the offset of the match member more explicitly. For now,
585 * we make the calculation as described here.
586 */
587
588/* 1.2 min length of match is 8 bytes */
589#define _MATCH_MIN_LENGTH_V3 8
590
591/**
592 * The offset of a 1.2 match object relative to fixed length of obj
593 */
594#define _MATCH_OFFSET_V3(fixed_obj_len) \\
595 ((fixed_obj_len) - _MATCH_MIN_LENGTH_V3)
596
597/**
598 * The "extra" length beyond the minimal 8 bytes of a match struct
599 * in an object
600 */
601#define _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len) \\
602 (OF_MATCH_BYTES(_TLV16_LEN(obj, _MATCH_OFFSET_V3(fixed_obj_len))) - \\
603 _MATCH_MIN_LENGTH_V3)
604
605/**
606 * The offset of an object following a match object for 1.2
607 */
608#define _OFFSET_FOLLOWING_MATCH_V3(obj, fixed_obj_len) \\
609 ((fixed_obj_len) + _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len))
610
611/**
612 * Get length of a match object from its wire representation
613 * @param obj An object with a match member
614 * @param match_offset The wire offset of the match object.
615 *
616 * See above; for 1.2,
617 * The match length is raw bytes but the actual space it takes
618 * up is padded for alignment to 64-bits
619 */
620#define _WIRE_MATCH_LEN(obj, match_offset) \\
621 (((obj)->version == OF_VERSION_1_0) ? %(match1)d : \\
622 (((obj)->version == OF_VERSION_1_1) ? %(match2)d : \\
623 _TLV16_LEN(obj, match_offset)))
624
625#define _WIRE_LEN_MIN 4
626
627/*
628 * Wrapper function for match len. There are cases where the wire buffer
629 * has not been set with the proper minimum length. In this case, the
630 * wire match len is interpretted as its minimum length, 4 bytes.
631 */
632
633static inline int
634wire_match_len(of_object_t *obj, int match_offset) {
635 int len;
636
637 len = _WIRE_MATCH_LEN(obj, match_offset);
638
639 return (len == 0) ? _WIRE_LEN_MIN : len;
640}
641
642#define _WIRE_MATCH_PADDED_LEN(obj, match_offset) \\
643 OF_MATCH_BYTES(wire_match_len((of_object_t *)(obj), (match_offset)))
644
645/**
646 * Macro to calculate variable offset of instructions member in flow mod
647 * @param obj An object of some type of flow modify/add/delete
648 *
649 * Get length of preceding match object and add to fixed length
650 * Applies only to version 1.2
651 */
652
653#define _FLOW_MOD_INSTRUCTIONS_OFFSET(obj) \\
654 _OFFSET_FOLLOWING_MATCH_V3(obj, %(flow_mod)d)
655
656/* The different flavors of flow mod all use the above */
657#define _FLOW_ADD_INSTRUCTIONS_OFFSET(obj) \\
658 _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
659#define _FLOW_MODIFY_INSTRUCTIONS_OFFSET(obj) \\
660 _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
661#define _FLOW_MODIFY_STRICT_INSTRUCTIONS_OFFSET(obj) \\
662 _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
663#define _FLOW_DELETE_INSTRUCTIONS_OFFSET(obj) \\
664 _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
665#define _FLOW_DELETE_STRICT_INSTRUCTIONS_OFFSET(obj) \\
666 _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
667
668/**
669 * Macro to calculate variable offset of instructions member in flow stats
670 * @param obj An object of type of_flow_mod_t
671 *
672 * Get length of preceding match object and add to fixed length
673 * Applies only to version 1.2 and 1.3
674 */
675
676#define _FLOW_STATS_ENTRY_INSTRUCTIONS_OFFSET(obj) \\
677 _OFFSET_FOLLOWING_MATCH_V3(obj, %(flow_stats)d)
678
679/**
680 * Macro to calculate variable offset of data (packet) member in packet_in
681 * @param obj An object of type of_packet_in_t
682 *
683 * Get length of preceding match object and add to fixed length
684 * Applies only to version 1.2 and 1.3
685 */
686
687#define _PACKET_IN_DATA_OFFSET(obj) \\
688 _OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
689%(packet_in)d : %(packet_in_1_3)d)
690
691/**
692 * Macro to calculate variable offset of data (packet) member in packet_out
693 * @param obj An object of type of_packet_out_t
694 *
695 * Find the length in the actions_len variable and add to the fixed len
696 * Applies only to version 1.2 and 1.3
697 */
698
699#define _PACKET_OUT_DATA_OFFSET(obj) (_PACKET_OUT_ACTION_LEN(obj) + \\
700 of_object_fixed_len[(obj)->version][OF_PACKET_OUT])
701
702/**
703 * Macro to map port numbers that changed across versions
704 * @param port The port_no_t variable holding the value
705 * @param ver The OpenFlow version from which the value was extracted
706 */
707#define OF_PORT_NO_VALUE_CHECK(port, ver) \\
708 if (((ver) == OF_VERSION_1_0) && ((port) > 0xff00)) (port) += 0xffff0000
709
710""" % dict(flow_mod=of_g.base_length[("of_flow_modify",of_g.VERSION_1_2)],
711 packet_in=of_g.base_length[("of_packet_in",of_g.VERSION_1_2)],
712 packet_in_1_3=of_g.base_length[("of_packet_in",of_g.VERSION_1_3)],
713 flow_stats=of_g.base_length[("of_flow_stats_entry",
714 of_g.VERSION_1_2)],
715 match1=of_g.base_length[("of_match_v1",of_g.VERSION_1_0)],
716 match2=of_g.base_length[("of_match_v2",of_g.VERSION_1_1)]))
717
718def gen_obj_id_macros(out):
719 """
720 Flow modify (add, delete) messages (and maybe others) use ID checks allowing
721 inheritance to use common accessor functions.
722 """
723 out.write("""
724/**
725 * Macro to detect if an object ID falls in the "flow mod" family of objects
726 * This includes add, modify, modify_strict, delete and delete_strict
727 */
728#define IS_FLOW_MOD_SUBTYPE(object_id) \\
729 (((object_id) == OF_FLOW_MODIFY) || \\
730 ((object_id) == OF_FLOW_MODIFY_STRICT) || \\
731 ((object_id) == OF_FLOW_DELETE) || \\
732 ((object_id) == OF_FLOW_DELETE_STRICT) || \\
733 ((object_id) == OF_FLOW_ADD))
734""")
735
736
737def top_c_gen(out, name):
738 """
739 Generate code for
740 @param out The file handle to write to
741 @param name The name of the file
742 """
743 common_top_matter(out, name)
744 # Generic C code that needs to go into loci.c can go here.
745 out.write("""
746/****************************************************************
747 *
748 * This file is divided into the following sections.
749 *
750 * Instantiate strings such as object names
751 * Special case macros for low level object access
752 * Per-class, per-member accessor definitions
753 * Per-class new/init function definitions
754 * Per-class new/init pointer instantiations
755 * Instantiate "set map" for pointer set fns
756 *
757 ****************************************************************/
758
Rich Lane34f40c72013-03-28 10:36:57 -0700759#ifdef __GNUC__
760#include <features.h>
761
762#if __GNUC_PREREQ(4,4)
Rich Lane12192032013-02-24 18:22:44 -0800763#pragma GCC optimize ("s")
Rich Lane34f40c72013-03-28 10:36:57 -0700764#endif
765
766#if __GNUC_PREREQ(4,6)
Rich Lane45676eb2013-03-26 14:28:31 -0700767#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
Rich Lane9d77b592013-03-27 11:28:10 -0700768#endif
Rich Lane12192032013-02-24 18:22:44 -0800769
Rich Lane34f40c72013-03-28 10:36:57 -0700770#endif
771
Rich Lanea06d0c32013-03-25 08:52:03 -0700772#include <loci/loci.h>
773#include <loci/of_object.h>
774#include "loci_log.h"
775
776""")
777 gen_object_enum_str(out)
778 gen_len_offset_macros(out)
779 gen_obj_id_macros(out)
780 if config_check("gen_unified_fns"):
781 gen_accessor_definitions(out)
782 gen_new_function_definitions(out)
783 gen_init_map(out)
784 out.write("\n/* This code should be broken out to a different file */\n")
785 gen_setup_from_add_fns(out)
786
787def type_data_c_gen(out, name):
788 common_top_matter(out, name)
789 c_type_maps.gen_type_maps(out)
790 c_type_maps.gen_length_array(out)
791
792################################################################
793# Top Matter
794################################################################
795
796def common_top_matter(out, name):
797 loxi_utils.gen_c_copy_license(out)
798 out.write("""\
799/****************************************************************
800 * File: %s
801 *
802 * DO NOT EDIT
803 *
804 * This file is automatically generated
805 *
806 ****************************************************************/
807
808""" % name)
809
810 if name[-2:] == ".h":
811 out.write("""
812#if !defined(%(h)s)
813#define %(h)s
814
815""" % dict(h=h_file_to_define(name)))
816
817def base_h_content(out):
818 """
819 Generate base header file content
820
821 @param out The output file object
822 """
823
824 # @fixme Supported version should be generated based on input to LoxiGen
825
826 out.write("""
827/*
828 * Base OpenFlow definitions. These depend only on standard C headers
829 */
830#include <string.h>
831#include <stdint.h>
832
833/* g++ requires this to pick up PRI, etc.
834 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
835 */
836#if !defined(__STDC_FORMAT_MACROS)
837#define __STDC_FORMAT_MACROS
838#endif
839#include <inttypes.h>
840
841#include <stdlib.h>
842#include <assert.h>
843#include <loci/loci_idents.h>
844
845/**
846 * Macro to enable debugging for LOCI.
847 *
848 * This enables debug output to stdout.
849 */
850#define OF_DEBUG_ENABLE
851
852#if defined(OF_DEBUG_ENABLE)
853#include <stdio.h> /* Currently for debugging */
854#define FIXME(str) do { \\
855 fprintf(stderr, "%s\\n", str); \\
856 exit(1); \\
857 } while (0)
858#define debug printf
859#else
860#define FIXME(str)
861#define debug(str, ...)
862#endif /* OF_DEBUG_ENABLE */
863
864/**
865 * The type of a function used by the LOCI dump/show functions to
866 * output text. Essentially the same signature as fprintf. May
867 * be called many times per invocation of e.g. of_object_show().
868 */
869typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
870
871/**
872 * Check if a version is supported
873 */
874#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
875
876""")
877 gen_version_enum(out)
878 out.write("\n")
879
880 # for c_name in of_g.ofp_constants:
881 # val = str(of_g.ofp_constants[c_name])
882 # out.write("#define %s %s\n" % (c_name, val))
883 # out.write("\n")
884
885 out.write("""
886typedef enum of_error_codes_e {
887 OF_ERROR_NONE = 0,
888 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
889 OF_ERROR_PARAM = -2, /* Bad parameter */
890 OF_ERROR_VERSION = -3, /* Version not supported */
891 OF_ERROR_RANGE = -4, /* End of list indication */
892 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
893 OF_ERROR_PARSE = -6, /* Error in parsing data */
894 OF_ERROR_INIT = -7, /* Uninitialized data */
895 OF_ERROR_UNKNOWN = -8 /* Unknown error */
896} of_error_codes_t;
897
898#define OF_ERROR_STRINGS "none", \\
899 "resource", \\
900 "parameter", \\
901 "version", \\
902 "range", \\
903 "incompatible", \\
904 "parse", \\
905 "init", \\
906 "unknown"
907
Rich Laneb157b0f2013-03-27 13:55:28 -0700908extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700909
Rich Lane53757732013-02-23 17:00:10 -0800910#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700911/* #define ASSERT(val) assert(val) */
912#define FORCE_FAULT *(volatile int *)0 = 1
913#define ASSERT(val) if (!(val)) \\
914 fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
915 FORCE_FAULT
Rich Lane53757732013-02-23 17:00:10 -0800916#else
917#define ASSERT(val)
918#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700919
920/*
921 * Some LOCI object accessors can fail, and it's easy to forget to check.
922 * On certain compilers we can trigger a warning if the error code
923 * is ignored.
924 */
925#ifndef DISABLE_WARN_UNUSED_RESULT
926#ifdef __GNUC__
927#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
928#else
929#define WARN_UNUSED_RESULT
930#endif
931#else
932#define WARN_UNUSED_RESULT
933#endif
934
935typedef union of_generic_u of_generic_t;
936typedef struct of_object_s of_object_t;
937
938/* Define ipv4 address as uint32 */
939typedef uint32_t of_ipv4_t;
940
941/* Table ID is the OF standard uint8 */
942typedef uint8_t of_table_id_t;
943
944#define OF_MAC_ADDR_BYTES 6
945typedef struct of_mac_addr_s {
946 uint8_t addr[OF_MAC_ADDR_BYTES];
947} of_mac_addr_t;
948
949#define OF_IPV6_BYTES 16
950typedef struct of_ipv6_s {
951 uint8_t addr[OF_IPV6_BYTES];
952} of_ipv6_t;
953
954extern const of_mac_addr_t of_mac_addr_all_ones;
955extern const of_mac_addr_t of_mac_addr_all_zeros;
956
957extern const of_ipv6_t of_ipv6_all_ones;
958extern const of_ipv6_t of_ipv6_all_zeros;
959
960/**
961 * Generic zero and all-ones values of size 16 bytes.
962 *
963 * IPv6 is longest data type we worry about for comparisons
964 */
965#define of_all_zero_value of_ipv6_all_zeros
966#define of_all_ones_value of_ipv6_all_ones
967
968/**
969 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
970 */
971#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
972 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
973#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
974 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
975
976/* The octets object is a struct holding pointer and length */
977typedef struct of_octets_s {
978 uint8_t *data;
979 int bytes;
980} of_octets_t;
981
982/* Macro to convert an octet object to a pointer; currently trivial */
983#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
984#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
985#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
986#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
987
988/* Currently these are categorized as scalars */
989typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
990typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
991typedef char of_desc_str_t[OF_DESC_STR_LEN];
992typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
993
994/* These are types which change across versions. */
995typedef uint32_t of_port_no_t;
996typedef uint16_t of_fm_cmd_t;
997typedef uint64_t of_wc_bmap_t;
998typedef uint64_t of_match_bmap_t;
999
1000#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
1001#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
1002#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
1003#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
1004#define MALLOC(bytes) malloc(bytes)
1005#define FREE(ptr) free(ptr)
1006
1007/** Try an operation and return on failure. */
1008#define OF_TRY(op) do { \\
1009 int _rv; \\
1010 if ((_rv = (op)) < 0) { \\
1011 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1012 return _rv; \\
1013 } \\
1014 } while (0)
1015
1016/* The extent of an OF match object is determined by its length field, but
1017 * aligned to 8 bytes
1018 */
1019
1020#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
1021
1022#if __BYTE_ORDER == __BIG_ENDIAN
1023#define U16_NTOH(val) (val)
1024#define U32_NTOH(val) (val)
1025#define U64_NTOH(val) (val)
1026#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
1027#define U16_HTON(val) (val)
1028#define U32_HTON(val) (val)
1029#define U64_HTON(val) (val)
1030#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
1031#else /* Little Endian */
1032#define U16_NTOH(val) (((val) >> 8) | ((val) << 8))
1033#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
1034 (((val) & 0x00ff0000) >> 8) | \\
1035 (((val) & 0x0000ff00) << 8) | \\
1036 (((val) & 0x000000ff) << 24))
1037#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
1038 (((val) & 0x00ff000000000000LL) >> 40) | \\
1039 (((val) & 0x0000ff0000000000LL) >> 24) | \\
1040 (((val) & 0x000000ff00000000LL) >> 8) | \\
1041 (((val) & 0x00000000ff000000LL) << 8) | \\
1042 (((val) & 0x0000000000ff0000LL) << 24) | \\
1043 (((val) & 0x000000000000ff00LL) << 40) | \\
1044 (((val) & 0x00000000000000ffLL) << 56))
1045#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
1046#define U16_HTON(val) U16_NTOH(val)
1047#define U32_HTON(val) U32_NTOH(val)
1048#define U64_HTON(val) U64_NTOH(val)
1049#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
1050#endif
1051
1052/****************************************************************
1053 *
1054 * The following are internal definitions used by the automatically
1055 * generated code. Users should not reference these definitions
1056 * as they may change between versions of this code
1057 *
1058 ****************************************************************/
1059
1060#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
1061 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
1062#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
1063#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
1064 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
1065
1066#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
1067 (FIXED_LEN + of_message_out_actions_len_get(obj))
1068
1069""")
1070
1071def external_h_top_matter(out, name):
1072 """
1073 Generate top matter for external header file
1074
1075 @param name The name of the output file
1076 @param out The output file object
1077 """
1078 common_top_matter(out, name)
1079 out.write("""
1080#include <loci/loci_base.h>
1081#include <loci/of_message.h>
1082#include <loci/of_match.h>
1083#include <loci/of_object.h>
1084#include <loci/of_wire_buf.h>
1085
1086/****************************************************************
1087 *
1088 * This file is divided into the following sections.
1089 *
1090 * A few object specific macros
1091 * Class typedefs (no struct definitions)
1092 * Per-data type accessor function typedefs
1093 * Per-class new/delete function typedefs
1094 * Per-class static delete functions
1095 * Per-class, per-member accessor declarations
1096 * Per-class structure definitions
1097 * Generic union (inheritance) definitions
1098 * Pointer set function declarations
1099 * Some special case macros
1100 *
1101 ****************************************************************/
1102""")
1103
1104def gen_top_static_functions(out):
1105 out.write("""
1106
1107#define _MAX_PARENT_ITERATIONS 4
1108/**
1109 * Iteratively update parent lengths thru hierarchy
1110 * @param obj The object whose length is being updated
1111 * @param delta The difference between the current and new lengths
1112 *
1113 * Note that this includes updating the object itself. It will
1114 * iterate thru parents.
1115 *
1116 * Assumes delta > 0.
1117 */
1118static inline void
1119of_object_parent_length_update(of_object_t *obj, int delta)
1120{
Rich Laneed79e0d2013-03-26 14:30:31 -07001121#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -07001122 int count = 0;
1123 of_wire_buffer_t *wbuf; /* For debug asserts only */
Rich Laneed79e0d2013-03-26 14:30:31 -07001124#endif
Rich Lanea06d0c32013-03-25 08:52:03 -07001125
1126 while (obj != NULL) {
1127 ASSERT(count++ < _MAX_PARENT_ITERATIONS);
1128 obj->length += delta;
1129 if (obj->wire_length_set != NULL) {
1130 obj->wire_length_set(obj, obj->length);
1131 }
Rich Laneed79e0d2013-03-26 14:30:31 -07001132#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -07001133 wbuf = obj->wire_object.wbuf;
Rich Laneed79e0d2013-03-26 14:30:31 -07001134#endif
Rich Lanea06d0c32013-03-25 08:52:03 -07001135
1136 /* Asserts for wire length checking */
1137 ASSERT(obj->length + obj->wire_object.obj_offset <=
1138 WBUF_CURRENT_BYTES(wbuf));
1139 if (obj->parent == NULL) {
1140 ASSERT(obj->length + obj->wire_object.obj_offset ==
1141 WBUF_CURRENT_BYTES(wbuf));
1142 }
1143
1144 obj = obj->parent;
1145 }
1146}
1147""")
1148
1149################################################################
1150#
1151################################################################
1152
1153def gen_version_enum(out):
1154 """
1155 Generate the enumerated type for versions in LoxiGen
1156 @param out The file object to which to write the decs
1157
1158 This just uses the wire versions for now
1159 """
1160 out.write("""
1161/**
1162 * Enumeration of OpenFlow versions
1163 *
1164 * The wire protocol numbers are currently used for values of the corresponding
1165 * version identifiers.
1166 */
1167typedef enum of_version_e {
1168 OF_VERSION_UNKNOWN = 0,
1169""")
1170
1171 is_first = True
1172 max = 0
1173 for v in of_g.wire_ver_map:
1174 if is_first:
1175 is_first = False
1176 else:
1177 out.write(",\n")
1178 if v > max:
1179 max = v
1180 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
1181
1182 out.write("""
1183} of_version_t;
1184
1185/**
1186 * @brief Use this when declaring arrays indexed by wire version
1187 */
1188#define OF_VERSION_ARRAY_MAX %d
1189""" % (max + 1))
1190
1191def gen_object_enum(out):
1192 """
1193 Generate the enumerated type for object identification in LoxiGen
1194 @param out The file object to which to write the decs
1195 """
1196 out.write("""
1197
1198/**
1199 * Enumeration of OpenFlow objects
1200 *
1201 * We enumerate the OpenFlow objects used internally. Note that some
1202 * message types are determined both by an outer type (message type like
1203 * stats_request) and an inner type (port stats). These are different
1204 * messages in ofC.
1205 *
1206 * These values are for internal use only. They will change with
1207 * different versions of ofC.
1208 */
1209
1210typedef enum of_object_id_e {
1211 /* Root object type */
1212 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
1213 OF_OBJECT = 0, /* Generic, untyped object */
1214
1215 /* OpenFlow message objects */
1216""")
1217 last = 0
1218 msg_count = 0
1219 for cls in of_g.ordered_messages:
1220 out.write(" %s = %d,\n" % (enum_name(cls),
1221 of_g.unified[cls]["object_id"]))
1222 msg_count = of_g.unified[cls]["object_id"] + 1
1223
1224 out.write("\n /* Non-message objects */\n")
1225 for cls in of_g.ordered_non_messages:
1226 out.write(" %s = %d,\n" % (enum_name(cls),
1227 of_g.unified[cls]["object_id"]))
1228 last = of_g.unified[cls]["object_id"]
1229 out.write("\n /* List objects */\n")
1230 for cls in of_g.ordered_list_objects:
1231 out.write(" %s = %d,\n" % (enum_name(cls),
1232 of_g.unified[cls]["object_id"]))
1233 last = of_g.unified[cls]["object_id"]
1234
1235 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1236 for cls in of_g.ordered_pseudo_objects:
1237 out.write(" %s = %d,\n" % (enum_name(cls),
1238 of_g.unified[cls]["object_id"]))
1239 last = of_g.unified[cls]["object_id"]
1240
1241 out.write("""
1242 OF_OBJECT_COUNT = %d
1243} of_object_id_t;
1244
Rich Laneb157b0f2013-03-27 13:55:28 -07001245extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -07001246
1247#define OF_MESSAGE_OBJECT_COUNT %d
1248""" % ((last + 1), msg_count))
1249
1250 # Generate object type range checking for inheritance classes
1251
1252 # @fixme These should be determined algorithmicly
1253 out.write("""
1254/*
1255 * Macros to check if an object ID is within an inheritance class range
1256 */
1257""")
1258 # Alphabetical order for 'last'
1259 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
1260 of_oxm="OF_OXM_VLAN_VID_MASKED",
1261 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
1262 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
1263 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
1264 # @FIXME add meter_band ?
1265 )
1266 for cls, last in last_ids.items():
1267 out.write("""
1268#define %(enum)s_FIRST_ID (%(enum)s + 1)
1269#define %(enum)s_LAST_ID %(last)s
1270#define %(enum)s_VALID_ID(id) \\
1271 ((id) >= %(enum)s_FIRST_ID && \\
1272 (id) <= %(enum)s_LAST_ID)
1273""" % dict(enum=enum_name(cls), last=last))
1274 out.write("""
1275/**
1276 * Function to check a wire ID
1277 * @param object_id The ID to check
1278 * @param base_object_id The inheritance parent, if applicable
1279 * @returns boolean: If base_object_id is an inheritance class, check if
1280 * object_id is valid as a subclass. Otherwise return 1.
1281 *
1282 * Note: Could check that object_id == base_object_id in the
1283 * second case.
1284 */
1285static inline int
1286of_wire_id_valid(int object_id, int base_object_id) {
1287 switch (base_object_id) {
1288 case OF_ACTION:
1289 return OF_ACTION_VALID_ID(object_id);
1290 case OF_OXM:
1291 return OF_OXM_VALID_ID(object_id);
1292 case OF_QUEUE_PROP:
1293 return OF_QUEUE_PROP_VALID_ID(object_id);
1294 case OF_TABLE_FEATURE_PROP:
1295 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
1296 case OF_INSTRUCTION:
1297 return OF_INSTRUCTION_VALID_ID(object_id);
1298 default:
1299 break;
1300 }
1301 return 1;
1302}
1303""")
1304
1305def gen_object_enum_str(out):
Rich Laneb157b0f2013-03-27 13:55:28 -07001306 out.write("\nconst char *const of_object_id_str[] = {\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001307 out.write(" \"of_object\",\n")
1308 for cls in of_g.ordered_messages:
1309 out.write(" \"%s\",\n" % cls)
1310 out.write("\n /* Non-message objects */\n")
1311 for cls in of_g.ordered_non_messages:
1312 out.write(" \"%s\",\n" % cls)
1313 out.write("\n /* List objects */\n")
1314 for cls in of_g.ordered_list_objects:
1315 out.write(" \"%s\",\n" % cls)
1316 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1317 for cls in of_g.ordered_pseudo_objects:
1318 out.write(" \"%s\",\n" % cls)
1319 out.write("\n \"of_unknown_object\"\n};\n")
1320
1321 # We'll do version strings while we're at it
1322 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001323 const char *const of_version_str[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001324 "Unknown OpenFlow Version",
1325 "OpenFlow-1.0",
1326 "OpenFlow-1.1",
1327 "OpenFlow-1.2"
1328};
1329
1330const of_mac_addr_t of_mac_addr_all_ones = {
1331 {
1332 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1333 }
1334};
1335/* Just to be explicit; static duration vars are init'd to 0 */
1336const of_mac_addr_t of_mac_addr_all_zeros = {
1337 {
1338 0, 0, 0, 0, 0, 0
1339 }
1340};
1341
1342const of_ipv6_t of_ipv6_all_ones = {
1343 {
1344 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1345 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1346 }
1347};
1348/* Just to be explicit; static duration vars are init'd to 0 */
1349const of_ipv6_t of_ipv6_all_zeros = {
1350 {
1351 0, 0, 0, 0, 0, 0, 0, 0,
1352 0, 0, 0, 0, 0, 0, 0, 0
1353 }
1354};
1355
1356/** @var of_error_strings
1357 * The error string map; use abs value to index
1358 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001359const char *const of_error_strings[] = { OF_ERROR_STRINGS };
Rich Lanea06d0c32013-03-25 08:52:03 -07001360""")
1361
1362################################################################
1363#
1364# Internal Utility Functions
1365#
1366################################################################
1367
1368
1369def acc_name(cls, m_name):
1370 """
1371 Generate the root name of an accessor function for typedef
1372 @param cls The class name
1373 @param m_name The member name
1374 """
1375 (m_type, get_rv) = get_acc_rv(cls, m_name)
1376 return "%s_%s" % (cls, m_type)
1377
1378def get_acc_rv(cls, m_name):
1379 """
1380 Determine the data type and return type for a get accessor.
1381
1382 The return type may be "void" or it may be the accessor type
1383 depending on the system configuration and on the data type.
1384
1385 @param cls The class name
1386 @param m_name The member name
1387 @return A pair (m_type, rv) where m_type is the unified type of the
1388 member and rv is the get_accessor return type
1389 """
1390 member = of_g.unified[cls]["union"][m_name]
1391 m_type = member["m_type"]
1392 rv = "int"
1393 if member_returns_val(cls, m_name):
1394 rv = m_type
1395 if m_type[-2:] == "_t":
1396 m_type = m_type[:-2]
1397
1398 return (m_type, rv)
1399
1400def param_list(cls, m_name, a_type):
1401 """
1402 Generate the parameter list (no parens) for an a_type accessor
1403 @param cls The class name
1404 @param m_name The member name
1405 @param a_type One of "set" or "get" or TBD
1406 """
1407 member = of_g.unified[cls]["union"][m_name]
1408 m_type = member["m_type"]
1409 params = ["%s_t *obj" % cls]
1410 if a_type == "set":
1411 if loxi_utils.type_is_scalar(m_type):
1412 params.append("%s %s" % (m_type, m_name))
1413 else:
1414 params.append("%s *%s" % (m_type, m_name))
1415 elif a_type in ["get", "bind"]:
1416 params.append("%s *%s" % (m_type, m_name))
1417 else:
1418 debug("Class %s, name %s Bad param list a_type: %s" %
1419 (cls, m_name, a_type))
1420 sys.exit(1)
1421 return params
1422
1423def typed_function_base(cls, m_name):
1424 """
1425 Generate the core name for accessors based on the type
1426 @param cls The class name
1427 @param m_name The member name
1428 """
1429 (m_type, get_rv) = get_acc_rv(cls, m_name)
1430 return "%s_%s" % (cls, m_type)
1431
1432def member_function_base(cls, m_name):
1433 """
1434 Generate the core name for accessors based on the member name
1435 @param cls The class name
1436 @param m_name The member name
1437 """
1438 return "%s_%s" % (cls, m_name)
1439
1440def field_ver_get(cls, m_name):
1441 """
1442 Generate a dict, indexed by wire version, giving a pair (type, offset)
1443
1444 @param cls The class name
1445 @param m_name The name of the class member
1446
1447 If offset is not known for m_name, the type
1448 A dict is used for more convenient indexing.
1449 """
1450 result = {}
1451
1452 for ver in of_g.unified[cls]:
1453 if type(ver) == type(0): # It's a version
1454 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1455 ref_ver = of_g.unified[cls][ver]["use_version"]
1456 members = of_g.unified[cls][ref_ver]["members"]
1457 else:
1458 members = of_g.unified[cls][ver]["members"]
1459 idx = loxi_utils.member_to_index(m_name, members)
1460 if (idx < 0):
1461 continue # Member not in this version
1462 m_type = members[idx]["m_type"]
1463 offset = members[idx]["offset"]
1464
1465 # If m_type is mixed, get wire version type from global data
1466 if m_type in of_g.of_mixed_types and \
1467 ver in of_g.of_mixed_types[m_type]:
1468 m_type = of_g.of_mixed_types[m_type][ver]
1469
1470 # add version to result list
1471 result[ver] = (m_type, offset)
1472
1473 return result
1474
1475def v3_match_offset_get(cls):
1476 """
1477 Return the offset of an OF 1.2 match in an object if it has such;
1478 otherwise return -1
1479 """
1480 result = field_ver_get(cls, "match")
1481 if of_g.VERSION_1_2 in result:
1482 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1483 return result[of_g.VERSION_1_2][1]
1484 return -1
1485
1486################################################################
1487#
1488# OpenFlow Object Definitions
1489#
1490################################################################
1491
1492
1493def gen_of_object_defs(out):
1494 """
1495 Generate low level of_object core operations
1496 @param out The file for output, already open
1497 """
1498
1499def gen_generics(out):
1500 for (cls, subclasses) in type_maps.inheritance_map.items():
1501 out.write("""
1502/**
1503 * Inheritance super class for %(cls)s
1504 *
1505 * This class is the union of %(cls)s classes. You can refer
1506 * to it untyped by refering to the member 'header' whose structure
1507 * is common across all sub-classes.
1508 */
1509
1510union %(cls)s_u {
1511 %(cls)s_header_t header; /* Generic instance */
1512""" % dict(cls=cls))
1513 for subcls in sorted(subclasses):
1514 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1515 out.write("};\n")
1516
1517def gen_struct_typedefs(out):
1518 """
1519 Generate typedefs for all struct objects
1520 @param out The file for output, already open
1521 """
1522
1523 out.write("\n/* LOCI inheritance parent typedefs */\n")
1524 for cls in type_maps.inheritance_map:
1525 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1526 out.write("\n/* LOCI object typedefs */\n")
1527 for cls in of_g.standard_class_order:
1528 if cls in type_maps.inheritance_map:
1529 continue
1530 if config_check("gen_fn_ptrs"):
1531 out.write("typedef struct %(cls)s_s %(cls)s_t;\n" % dict(cls=cls))
1532 else:
1533 template = "typedef of_object_t %(cls)s_t;\n"
1534 out.write(template % dict(cls=cls))
1535
1536 out.write("""
1537/****************************************************************
1538 *
1539 * Additional of_object defines
1540 * These are needed for some static inline ops, so we put them here.
1541 *
1542 ****************************************************************/
1543
1544/* Delete an OpenFlow object without reference to its type */
1545extern void of_object_delete(of_object_t *obj);
1546
1547""")
1548
1549def gen_generic_union(out):
1550 """
1551 Generate the generic union object composing all LOCI objects
1552
1553 @param out The file to which to write the decs
1554 """
1555 out.write("""
1556/**
1557 * The common LOCI object is a union of all possible objects.
1558 */
1559union of_generic_u {
1560 of_object_t object; /* Common base class with fundamental accessors */
1561
1562 /* Message objects */
1563""")
1564 for cls in of_g.ordered_messages:
1565 out.write(" %s_t %s;\n" % (cls, cls))
1566 out.write("\n /* Non-message composite objects */\n")
1567 for cls in of_g.ordered_non_messages:
1568 if cls in type_maps.inheritance_map:
1569 continue
1570 out.write(" %s_t %s;\n" % (cls, cls))
1571 out.write("\n /* List objects */\n")
1572 for cls in of_g.ordered_list_objects:
1573 out.write(" %s_t %s;\n" % (cls, cls))
1574 out.write("};\n")
1575
1576def gen_common_struct_definitions(out):
1577 out.write("""
1578/****************************************************************
1579 *
1580 * Unified structure definitions
1581 *
1582 ****************************************************************/
1583
1584struct of_object_s {
1585 /* Common members */
1586%(common)s
1587};
1588""" % dict(common=of_g.base_object_members))
1589
1590def gen_flow_add_setup_function_declarations(out):
1591 """
1592 Add the declarations for functions that can be initialized
1593 by a flow add. These are defined external to LOXI.
1594 """
1595
1596 out.write("""
1597/****************************************************************
1598 * Functions for objects that can be initialized by a flow add message.
1599 * These are defined in a non-autogenerated file
1600 ****************************************************************/
1601
1602/**
1603 * @brief Set up a flow removed message from the original add
1604 * @param obj The flow removed message being updated
1605 * @param flow_add The flow_add message to use
1606 *
1607 * Initialize the following fields of obj to be identical
1608 * to what was originally on the wire from the flow_add object:
1609 * match
1610 * cookie
1611 * priority
1612 * idle_timeout
1613 * hard_timeout
1614 *
1615 */
1616
1617extern int
1618of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1619 of_flow_add_t *flow_add);
1620
1621
1622/**
1623 * @brief Set up the packet in match structure from the original add
1624 * @param obj The packet in message being updated
1625 * @param flow_add The flow_add message to use
1626 * @returns Indigo error code. Does not return a version error if
1627 * the version does not require initializing obj.
1628 *
1629 * Initialize the match member of obj to be identical to what was originally
1630 * on the wire from the flow_add object. If applicable, the table ID is also
1631 * initialized from the flow_add object.
1632 *
1633 * This API applies to 1.2 and later only.
1634 */
1635
1636extern int
1637of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1638 of_flow_add_t *flow_add);
1639
1640
1641/**
1642 * @brief Set up the flow stats entry from the original add
1643 * @param obj The packet in message being updated
1644 * @param flow_add The flow_add message to use
1645 * @param effects Optional actions or instructions; see below.
1646 *
1647 * Initialize the following fields of obj to be identical
1648 * to what was originally on the wire from the flow_add object:
1649 * match
1650 * actions/instructions (effects)
1651 * cookie
1652 * priority
1653 * idle_timeout
1654 * hard_timeout
1655 *
1656 * Note that the actions/instructions of a flow may be modified by a
1657 * subsequent flow modify message. To facilitate implementations,
1658 * the "effects" parameter is provided. If effects is NULL, the
1659 * actions/instructions are taken from the flow_add message.
1660 * Otherwise, effects is coerced to the proper type (actions or
1661 * instructions) and used to init obj.
1662 */
1663
1664extern int
1665of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1666 of_flow_add_t *flow_add,
1667 of_object_t *effects);
1668""")
1669
1670def gen_struct_definitions(out):
1671 """
1672 Generate the declaration of all of_ C structures
1673
1674 @param out The file to which to write the decs
1675 """
1676
1677 # This should only get called if gen_fn_ptr is true in code_gen_config
1678 if not config_check("gen_fn_ptrs"):
1679 debug("Error: gen_struct_defs called, but no fn ptrs set")
1680 return
1681
1682 for cls in of_g.standard_class_order:
1683 if cls in type_maps.inheritance_map:
1684 continue # These are generated elsewhere
1685 note = ""
1686 if loxi_utils.class_is_message(cls):
1687 note = " /* Class is message */"
1688 out.write("struct %s_s {%s\n" % (cls, note))
1689 out.write(""" /* Common members */
1690%s
1691 /* Class specific members */
1692""" % of_g.base_object_members)
1693 if loxi_utils.class_is_list(cls):
1694 out.write("""
1695 %(cls)s_first_f first;
1696 %(cls)s_next_f next;
1697 %(cls)s_append_bind_f append_bind;
1698 %(cls)s_append_f append;
1699};
1700
1701""" % {"cls": cls})
1702 continue # All done with list object
1703
1704 # Else, not a list instance; add accessors for all data members
1705 for m_name in of_g.ordered_members[cls]:
1706 if m_name in of_g.skip_members:
1707 # These members (length, etc) are handled internally
1708 continue
1709 f_name = acc_name(cls, m_name)
1710 out.write(" %s_get_f %s;\n" % (f_name, m_name + "_get"))
1711 out.write(" %s_set_f %s;\n" % (f_name, m_name + "_set"))
1712 out.write("};\n\n")
1713
1714
1715################################################################
1716#
1717# List accessor code generation
1718#
1719# Currently these all implement copy on read semantics
1720#
1721################################################################
1722
1723def init_call(e_type, obj, ver, length, cw):
1724 """
1725 Generate the init call given the strings for params
1726 """
1727 hdr = "" # If inheritance type, coerce to hdr object
1728 obj_name = obj
1729 if e_type in type_maps.inheritance_map:
1730 hdr = "_header"
1731 obj_name = "(%s_header_t *)" % e_type + obj
1732
1733 return """\
1734%(e_type)s%(hdr)s_init(%(obj_name)s,
1735 %(ver)s, %(length)s, %(cw)s)\
1736""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1737 length=length, cw=cw)
1738
1739def gen_list_first(out, cls, e_type):
1740 """
1741 Generate the body of a list_first operation
1742 @param cls The class name for which code is being generated
1743 @param e_type The element type of the list
1744 @param out The file to which to write
1745 """
1746 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1747 if e_type in type_maps.inheritance_map:
1748 len_str = "obj->header.length"
1749 else:
1750 len_str = "obj->length"
1751
1752 out.write("""
1753/**
1754 * Associate an iterator with a list
1755 * @param list The list to iterate over
1756 * @param obj The list entry iteration pointer
1757 * @return OF_ERROR_RANGE if the list is empty (end of list)
1758 *
1759 * The obj instance is completely initialized. The caller is responsible
1760 * for cleaning up any wire buffers associated with obj before this call
1761 */
1762
1763int
1764%(cls)s_first(%(cls)s_t *list,
1765 %(e_type)s_t *obj)
1766{
1767 int rv;
1768
1769 %(i_call)s;
1770 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1771 return rv;
1772 }
1773""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1774
1775 # Special case flow_stats_entry lists
1776
1777 out.write("""
1778 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1779 list->length);
1780 if (%(len_str)s == 0) {
1781 return OF_ERROR_PARSE;
1782 }
1783
1784 return rv;
1785}
1786""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1787
1788
1789def gen_bind(out, cls, m_name, m_type):
1790 """
1791 Generate the body of a bind function
1792 @param out The file to which to write
1793 @param cls The class name for which code is being generated
1794 @param m_name The name of the data member
1795 @param m_type The type of the data member
1796 """
1797
1798 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1799
1800 i_call = init_call(e_type, "child", "parent->version", "0", "1")
1801
1802 out.write("""
1803/**
1804 * Bind the child object to the parent object for read processing
1805 * @param parent The parent object
1806 * @param child The child object
1807 *
1808 * The child obj instance is completely initialized.
1809 */
1810
1811int
1812%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
1813 %(e_type)s_t *child)
1814{
1815 int rv;
1816
1817 %(i_call)s;
1818
1819 /* Derive offset and length of child in parent */
1820 OF_TRY(of_object_child_attach(parent, child,
1821 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1822 return rv;
1823 }
1824""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1825
1826 # Special case flow_stats_entry lists
1827
1828 out.write("""
1829 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1830 list->length);
1831 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1832 return OF_ERROR_PARSE;
1833 }
1834
1835 return rv;
1836}
1837""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1838
1839
1840def gen_list_next(out, cls, e_type):
1841 """
1842 Generate the body of a list_next operation
1843 @param cls The class name for which code is being generated
1844 @param e_type The element type of the list
1845 @param out The file to which to write
1846 """
1847
1848 if e_type in type_maps.inheritance_map:
1849 len_str = "obj->header.length"
1850 else:
1851 len_str = "obj->length"
1852
1853 out.write("""
1854/**
1855 * Advance an iterator to the next element in a list
1856 * @param list The list being iterated
1857 * @param obj The list entry iteration pointer
1858 * @return OF_ERROR_RANGE if already at the last entry on the list
1859 *
1860 */
1861
1862int
1863%(cls)s_next(%(cls)s_t *list,
1864 %(e_type)s_t *obj)
1865{
1866 int rv;
1867
1868 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1869 return rv;
1870 }
1871
1872 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1873 list->length);
1874
1875 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1876 return OF_ERROR_PARSE;
1877 }
1878
1879 return rv;
1880}
1881""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1882
1883def gen_list_append(out, cls, e_type):
1884 """
1885 Generate the body of a list append functions
1886 @param cls The class name for which code is being generated
1887 @param e_type The element type of the list
1888 @param out The file to which to write
1889 """
1890
1891 out.write("""
1892/**
1893 * Set up to append an object of type %(e_type)s to an %(cls)s.
1894 * @param list The list that is prepared for append
1895 * @param obj Pointer to object to hold data to append
1896 *
1897 * The obj instance is completely initialized. The caller is responsible
1898 * for cleaning up any wire buffers associated with obj before this call.
1899 *
1900 * See the generic documentation for of_list_append_bind.
1901 */
1902
1903int
1904%(cls)s_append_bind(%(cls)s_t *list,
1905 %(e_type)s_t *obj)
1906{
1907 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1908}
1909
1910/**
1911 * Append an item to a %(cls)s list.
1912 *
1913 * This copies data from item and leaves item untouched.
1914 *
1915 * See the generic documentation for of_list_append.
1916 */
1917
1918int
1919%(cls)s_append(%(cls)s_t *list,
1920 %(e_type)s_t *item)
1921{
1922 return of_list_append((of_object_t *)list, (of_object_t *)item);
1923}
1924
1925""" % dict(cls=cls, e_type=e_type))
1926
1927def gen_list_accessors(out, cls):
1928 e_type = loxi_utils.list_to_entry_type(cls)
1929 gen_list_first(out, cls, e_type)
1930 gen_list_next(out, cls, e_type)
1931 gen_list_append(out, cls, e_type)
1932
1933################################################################
1934#
1935# Accessor Functions
1936#
1937################################################################
1938
1939
1940def gen_accessor_declarations(out):
1941 """
1942 Generate the declaration of each version independent accessor
1943
1944 @param out The file to which to write the decs
1945 """
1946
1947 out.write("""
1948/****************************************************************
1949 *
1950 * Unified, per-member accessor function declarations
1951 *
1952 ****************************************************************/
1953""")
1954 for cls in of_g.standard_class_order:
1955 if cls in type_maps.inheritance_map:
1956 continue
1957 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1958 for m_name in of_g.ordered_members[cls]:
1959 if m_name in of_g.skip_members:
1960 continue
1961 m_type = loxi_utils.member_base_type(cls, m_name)
1962 base_name = "%s_%s" % (cls, m_name)
1963 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1964 get_ret_type = accessor_return_type("get", m_type)
1965 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1966 set_ret_type = accessor_return_type("set", m_type)
1967 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1968 bind_ret_type = accessor_return_type("bind", m_type)
1969
1970 if loxi_utils.type_is_of_object(m_type):
1971 # Generate bind accessors, but not get accessor
1972 out.write("""
1973extern %(set_ret_type)s %(base_name)s_set(
1974 %(sparams)s);
1975extern %(bind_ret_type)s %(base_name)s_bind(
1976 %(bparams)s);
1977extern %(m_type)s *%(cls)s_%(m_name)s_get(
1978 %(cls)s_t *obj);
1979""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1980 m_name=m_name, m_type=m_type, cls=cls,
1981 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1982 else:
1983 out.write("""
1984extern %(set_ret_type)s %(base_name)s_set(
1985 %(sparams)s);
1986extern %(get_ret_type)s %(base_name)s_get(
1987 %(gparams)s);
1988""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1989 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
1990
1991 if loxi_utils.class_is_list(cls):
1992 e_type = loxi_utils.list_to_entry_type(cls)
1993 out.write("""
1994extern int %(cls)s_first(
1995 %(cls)s_t *list, %(e_type)s_t *obj);
1996extern int %(cls)s_next(
1997 %(cls)s_t *list, %(e_type)s_t *obj);
1998extern int %(cls)s_append_bind(
1999 %(cls)s_t *list, %(e_type)s_t *obj);
2000extern int %(cls)s_append(
2001 %(cls)s_t *list, %(e_type)s_t *obj);
2002
2003/**
2004 * Iteration macro for list of type %(cls)s
2005 * @param list Pointer to the list being iterated over of
2006 * type %(cls)s
2007 * @param elt Pointer to an element of type %(e_type)s
2008 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
2009 */
2010#define %(u_cls)s_ITER(list, elt, rv) \\
2011 for ((rv) = %(cls)s_first((list), (elt)); \\
2012 (rv) == OF_ERROR_NONE; \\
2013 (rv) = %(cls)s_next((list), (elt)))
2014""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
2015
2016
2017def wire_accessor(m_type, a_type):
2018 """
2019 Returns the name of the a_type accessor for low level wire buff offset
2020 @param m_type The member type
2021 @param a_type The accessor type (set or get)
2022 """
2023 # Strip off _t if present
2024 if m_type in of_g.of_base_types:
2025 m_type = of_g.of_base_types[m_type]["short_name"]
2026 if m_type in of_g.of_mixed_types:
2027 m_type = of_g.of_mixed_types[m_type]["short_name"]
2028 if m_type[-2:] == "_t":
2029 m_type = m_type[:-2]
2030 if m_type == "octets":
2031 m_type = "octets_data"
2032 return "of_wire_buffer_%s_%s" % (m_type, a_type)
2033
2034def get_len_macro(cls, m_type, version):
2035 """
2036 Get the length macro for m_type in cls
2037 """
2038 if m_type.find("of_match") == 0:
2039 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
2040 if m_type.find("of_list_oxm") == 0:
2041 return "wire_match_len(obj, 0) - 4"
2042 if loxi_utils.class_is_tlv16(m_type):
2043 return "_TLV16_LEN(obj, offset)"
2044 if cls == "of_packet_out" and m_type == "of_list_action_t":
2045 return "_PACKET_OUT_ACTION_LEN(obj)"
2046 # Default is everything to the end of the object
2047 return "_END_LEN(obj, offset)"
2048
2049def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
2050 """
2051 Generate the sub-object offset and length calculations for accessors
2052 @param out File being written
2053 @param m_name Name of member
2054 @param version Wire version being processed
2055 @param a_type The accessor type (set or get)
2056 @param m_type The original member type
2057 @param offset The offset of the object or -1 if not fixed
2058 """
2059 # determine offset
2060 o_str = "%d" % offset # Default is fixed length
2061 if offset == -1:
2062 # There are currently 4 special cases for this
2063 # In general, get offset and length of predecessor
2064 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
2065 pass
2066 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
2067 pass
2068 elif (cls == "of_packet_in" and m_name == "data"):
2069 pass
2070 elif (cls == "of_packet_out" and m_name == "data"):
2071 pass
2072 else:
2073 debug("Error: Unknown member with offset == -1")
2074 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
2075 sys.exit(1)
2076 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
2077
2078 out.write("""\
2079 offset = %s;
2080""" % o_str);
2081
2082 # This could be moved to main body but for version check
2083 if not loxi_utils.type_is_scalar(m_type):
2084 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
2085 m_type == "of_match_t":
2086 len_macro = get_len_macro(cls, m_type, version)
2087 else:
2088 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
2089 out.write(" cur_len = %s;\n" % len_macro)
2090 out.write(" break;\n")
2091
2092def length_of(m_type, version):
2093 """
2094 Return the length of a type based on the version
2095 """
2096 if m_type in of_g.of_mixed_types:
2097 m_type = of_g.of_mixed_types[m_type][version]
2098 if m_type in of_g.of_base_types:
2099 return of_g.of_base_types[m_type]["bytes"]
2100 if (m_type[:-2], version) in of_g.base_length:
2101 return of_g.base_length[(m_type[:-2], version)]
2102 print "Unknown length request", m_type, version
2103 sys.exit(1)
2104
2105
2106def gen_get_accessor_body(out, cls, m_type, m_name):
2107 """
2108 Generate the common operations for a get accessor
2109 """
2110 if loxi_utils.type_is_scalar(m_type):
2111 ver = "" # See if version required for scalar update
2112 if m_type in of_g.of_mixed_types:
2113 ver = "ver, "
2114 out.write("""\
2115 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
2116""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
2117
2118 if m_type == "of_port_no_t":
2119 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
2120 elif m_type == "of_octets_t":
2121 out.write("""\
2122 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
2123 %(m_name)s->bytes = cur_len;
2124 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
2125""" % dict(m_name=m_name))
2126 elif m_type == "of_match_t":
2127 out.write("""
2128 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
2129 match_octets.bytes = cur_len;
2130 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
2131 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
2132""" % dict(m_name=m_name))
2133 else:
2134 out.write("""
2135 /* Initialize child */
2136 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
2137 /* Attach to parent */
2138 %(m_name)s->parent = (of_object_t *)obj;
2139 %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
2140 %(m_name)s->wire_object.obj_offset = abs_offset;
2141 %(m_name)s->wire_object.owned = 0;
2142 %(m_name)s->length = cur_len;
2143""" % dict(m_type=m_type[:-2], m_name=m_name))
2144
2145
2146def gen_set_accessor_body(out, cls, m_type, m_name):
2147 """
2148 Generate the contents of a set accessor
2149 """
2150 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2151 ver = "" # See if version required for scalar update
2152 if m_type in of_g.of_mixed_types:
2153 ver = "ver, "
2154 cur_len = "" # See if version required for scalar update
2155 if m_type == "of_octets_t":
2156 cur_len = ", cur_len"
2157 out.write("""\
2158 new_len = %(m_name)s->bytes;
2159 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
2160""" % dict(m_name=m_name))
2161 out.write("""\
2162 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
2163""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
2164 m_name=m_name))
2165
2166 elif m_type == "of_match_t":
2167 out.write("""
2168 /* Match object */
2169 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
2170 new_len = match_octets.bytes;
2171 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
2172 match_octets.data, new_len);
2173 /* Free match serialized octets */
2174 FREE(match_octets.data);
2175""" % dict(m_name=m_name))
2176
2177 else: # Other object type
2178 out.write("\n /* LOCI object type */")
2179 # Need to special case OXM list
2180 out.write("""
2181 new_len = %(m_name)s->length;
2182 /* If underlying buffer already shared; nothing to do */
2183 if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
2184 of_wire_buffer_grow(wbuf, abs_offset + new_len);
2185 /* Verify that the offsets are correct */
2186 ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
2187 /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
2188 return %(ret_success)s;
2189 }
2190
2191 /* Otherwise, replace existing object in data buffer */
2192 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
2193 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
2194""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
2195
2196 if not loxi_utils.type_is_scalar(m_type):
2197 if cls == "of_packet_out" and m_type == "of_list_action_t":
2198 out.write("""
2199 /* Special case for setting action lengths */
2200 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
2201""" % dict(m_name=m_name))
2202 elif m_type not in ["of_match_t", "of_octets_t"]:
2203 out.write("""
2204 /* @fixme Shouldn't this precede copying value's data to buffer? */
2205 if (%(m_name)s->wire_length_set != NULL) {
2206 %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
2207 }
2208""" % dict(m_name=m_name))
2209 out.write("""
2210 /* Not scalar, update lengths if needed */
2211 delta = new_len - cur_len;
2212 if (delta != 0) {
2213 /* Update parent(s) */
2214 of_object_parent_length_update((of_object_t *)obj, delta);
2215 }
2216""")
2217
2218def obj_assert_check(cls):
2219 """
2220 The body of the assert check for an accessor
2221 We allow all versions of add/delete/modify to use the same accessors
2222 """
2223 if cls in ["of_flow_modify", "of_flow_modify_strict",
2224 "of_flow_delete", "of_flow_delete_strict",
2225 "of_flow_add"]:
2226 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
2227 else:
2228 return "obj->object_id == %s" % cls.upper()
2229
2230def gen_of_object_get(out, cls, m_name, m_type):
2231 sub_cls = m_type[:-2]
2232 out.write("""
2233/**
2234 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
2235 * a %(cls)s instance.
2236 *
2237 * @param obj Pointer to the source of type %(cls)s_t
2238 * @returns A pointer to a new instance of type %(m_type)s whose contents
2239 * match that of %(m_name)s from source
2240 * @returns NULL if an error occurs
2241 */
2242%(m_type)s *
2243%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
2244 %(m_type)s _%(m_name)s;
2245 %(m_type)s *_%(m_name)s_ptr;
2246
2247 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
2248 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
2249 return _%(m_name)s_ptr;
2250}
2251""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
2252
2253def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
2254 """
2255 Generate the body of a set or get accessor function
2256
2257 @param out The file to which to write the decs
2258 @param cls The class name
2259 @param m_name The member name
2260 @param ver_type_map Maps (type, offset) pairs to a list of versions
2261 @param a_type The accessor type, set or get
2262 @param m_type The original member type
2263
2264 The type values in ver_type_map are now ignored as we've pushed down
2265 the type munging to the lower level.
2266
2267 This is unified because the version switch case processing is the
2268 same for both set and get
2269 """
2270 out.write("""{
2271 of_wire_buffer_t *wbuf;
2272 int offset = 0; /* Offset of value relative to the start obj */
2273 int abs_offset; /* Offset of value relative to start of wbuf */
2274 of_version_t ver;
2275""")
2276
2277 if not loxi_utils.type_is_scalar(m_type):
2278 out.write("""\
2279 int cur_len = 0; /* Current length of object data */
2280""")
2281 if a_type == "set":
2282 out.write("""\
2283 int new_len, delta; /* For set, need new length and delta */
2284""")
2285
2286 # For match, need octet string for set/get
2287 if m_type == "of_match_t":
2288 out.write("""\
2289 of_octets_t match_octets; /* Serialized string for match */
2290""")
2291
2292 out.write("""
2293 ASSERT(%(assert_str)s);
2294 ver = obj->version;
2295 wbuf = OF_OBJECT_TO_WBUF(obj);
2296 ASSERT(wbuf != NULL);
2297
2298 /* By version, determine offset and current length (where needed) */
2299 switch (ver) {
2300""" % dict(assert_str=obj_assert_check(cls)))
2301
2302 for first in sorted(ver_type_map):
2303 (prev_t, prev_o) = ver_type_map[first]
2304 prev_len = length_of(prev_t, first)
2305 prev = first
2306 out.write(" case %s:\n" % of_g.wire_ver_map[first])
2307 break
2308
2309 for next in sorted(ver_type_map):
2310 if next == first:
2311 continue
2312
2313 (t, o) = ver_type_map[next]
2314 cur_len = length_of(t, next)
2315 if o == prev_o and cur_len == prev_len:
2316 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2317 continue
2318 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
2319 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2320 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
2321
2322 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
2323 out.write("""\
2324 default:
2325 ASSERT(0);
2326 }
2327
2328 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
2329 ASSERT(abs_offset >= 0);
2330""")
2331 if not loxi_utils.type_is_scalar(m_type):
2332 out.write(" ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
2333
2334 # Now generate the common accessor code
2335 if a_type in ["get", "bind"]:
2336 gen_get_accessor_body(out, cls, m_type, m_name)
2337 else:
2338 gen_set_accessor_body(out, cls, m_type, m_name)
2339
2340 out.write("""
2341 OF_LENGTH_CHECK_ASSERT(obj);
2342
2343 return %s;
2344}
2345""" % accessor_return_success(a_type, m_type))
2346
2347def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
2348 """
2349 For generating the bind call for OF sub-objects
2350 """
2351
2352 params = ",\n ".join(param_list(cls, m_name, "bind"))
2353 out.write("""
2354/**
2355 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
2356 * member %(m_name)s
2357 * @param obj Pointer to an object of type %(cls)s.
2358 * @param %(m_name)s Pointer to the child object of type
2359 * %(m_type)s to be filled out.
2360 * \ingroup %(cls)s
2361 *
2362 * The parameter %(m_name)s is filled out to point to the same underlying
2363 * wire buffer as its parent.
2364 *
2365 */
2366""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2367
2368 ret_type = accessor_return_type("bind", m_type)
2369 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
2370 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
2371
2372def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
2373 """
2374 For generating the get call for non- OF sub-objects
2375 """
2376 params = ",\n ".join(param_list(cls, m_name, "get"))
2377 out.write("""
2378/**
2379 * Get %(m_name)s from an object of type %(cls)s.
2380 * @param obj Pointer to an object of type %(cls)s.
2381 * @param %(m_name)s Pointer to the child object of type
2382 * %(m_type)s to be filled out.
2383 *
2384 */
2385""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2386
2387 ret_type = accessor_return_type("get", m_type)
2388 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
2389 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
2390
2391def gen_accessor_definitions(out):
2392 """
2393 Generate the body of each version independent accessor
2394
2395 @param out The file to which to write the decs
2396 """
2397
2398 out.write("""
2399/****************************************************************
2400 *
2401 * Unified accessor function definitions
2402 *
2403 ****************************************************************/
2404""")
2405 for cls in of_g.standard_class_order:
2406 if cls in type_maps.inheritance_map:
2407 continue
2408 out.write("\n/* Unified accessor functions for %s */\n" % cls)
2409 if loxi_utils.class_is_list(cls):
2410 gen_list_accessors(out, cls)
2411 continue
2412 out.write("/** \\ingroup %s \n * @{ */\n" % cls)
2413 for m_name in of_g.ordered_members[cls]:
2414 if m_name in of_g.skip_members:
2415 continue
2416 m_type = loxi_utils.member_base_type(cls, m_name)
2417 ver_type_map = field_ver_get(cls, m_name)
2418
2419 # Generate get/bind pending on member type
2420 # FIXME: Does this do the right thing for match?
2421 if loxi_utils.type_is_of_object(m_type):
2422 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
2423 gen_of_object_get(out, cls, m_name, m_type)
2424 else:
2425 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
2426
2427 # Now generate set accessor for all objects
2428 params = ",\n ".join(param_list(cls, m_name, "set"))
2429 out.write("""
2430/**
2431 * Set %(m_name)s in an object of type %(cls)s.
2432 * @param obj Pointer to an object of type %(cls)s.
2433""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2434 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2435 out.write("""\
2436 * @param %(m_name)s The value to write into the object
2437 */
2438""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2439 else:
2440 out.write("""\
2441 * @param %(m_name)s Pointer to the child of type %(m_type)s.
2442 *
2443 * If the child's wire buffer is the same as the parent's, then
2444 * nothing is done as the changes have already been registered in the
2445 * parent. Otherwise, the data in the child's wire buffer is inserted
2446 * into the parent's and the appropriate lengths are updated.
2447 */
2448""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2449 ret_type = accessor_return_type("set", m_type)
2450 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
2451 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
2452
2453 out.write("\n/** @} */\n")
2454
2455def gen_acc_pointer_typedefs(out):
2456 """
2457 Generate the function pointer typedefs for in-struct accessors
2458 @param out The file to which to write the typedefs
2459 """
2460
2461 out.write("""
2462/****************************************************************
2463 *
2464 * Accessor function pointer typedefs
2465 *
2466 ****************************************************************/
2467
2468/*
2469 * Generic accessors:
2470 *
2471 * Many objects have a length represented in the wire buffer
2472 * wire_length_get and wire_length_set access these values directly on the
2473 * wire.
2474 *
2475 * Many objects have a length represented in the wire buffer
2476 * wire_length_get and wire_length_set access these values directly on the
2477 * wire.
2478 *
2479 * FIXME: TBD if wire_length_set and wire_type_set are required.
2480 */
2481typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
2482typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
2483typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
2484typedef void (*of_wire_type_set_f)(of_object_t *obj, of_object_id_t id);
2485""")
2486 # If not using function pointers in classes, don't gen typedefs below
2487 if not config_check("gen_fn_ptrs"):
2488 return
2489
2490 # For each class, for each type it uses, generate a typedef
2491 for cls in of_g.standard_class_order:
2492 if cls in type_maps.inheritance_map:
2493 continue
2494 out.write("\n/* Accessor function pointer typedefs for %s */\n" % cls)
2495 types_done = list()
2496 for m_name in of_g.ordered_members[cls]:
2497 (m_type, get_rv) = get_acc_rv(cls, m_name)
2498 if (m_type, get_rv) in types_done:
2499 continue
2500 types_done.append((m_type, get_rv))
2501 fn = "%s_%s" % (cls, m_type)
2502 params = ", ".join(param_list(cls, m_name, "get"))
2503 out.write("typedef int (*%s_get_f)(\n %s);\n" %
2504 (fn, params))
2505
2506 params = ", ".join(param_list(cls, m_name, "set"))
2507 out.write("typedef int (*%s_set_f)(\n %s);\n" %
2508 (fn, params))
2509 if loxi_utils.class_is_list(cls):
2510 obj_type = loxi_utils.list_to_entry_type(cls)
2511 out.write("""typedef int (*%(cls)s_first_f)(
2512 %(cls)s_t *list,
2513 %(obj_type)s_t *obj);
2514typedef int (*%(cls)s_next_f)(
2515 %(cls)s_t *list,
2516 %(obj_type)s_t *obj);
2517typedef int (*%(cls)s_append_bind_f)(
2518 %(cls)s_t *list,
2519 %(obj_type)s_t *obj);
2520typedef int (*%(cls)s_append_f)(
2521 %(cls)s_t *list,
2522 %(obj_type)s_t *obj);
2523""" % {"cls":cls, "obj_type":obj_type})
2524
2525# out.write("""
2526# typedef int (*%(cls)s_get_f)(
2527# %(cls)s_t *list,
2528# %(obj_type)s_t *obj, int index);
2529# typedef int (*%(cls)s_set_f)(
2530# %(cls)s_t *list,
2531# %(obj_type)s_t *obj, int index);
2532# typedef int (*%(cls)s_append_f)(
2533# %(cls)s_t *list,
2534# %(obj_type)s_t *obj, int index);
2535# typedef int (*%(cls)s_insert_f)(
2536# %(cls)s_t *list,
2537# %(obj_type)s_t *obj, int index);
2538# typedef int (*%(cls)s_remove_f)(
2539# %(cls)s_t *list,
2540# int index);
2541# """ % {"cls":cls, "obj_type":obj_type})
2542
2543################################################################
2544#
2545# New/Delete Function Definitions
2546#
2547################################################################
2548
2549
2550################################################################
2551# First, some utility functions for new/delete
2552################################################################
2553
2554def del_function_proto(cls):
2555 """
2556 Return the prototype for the delete operator for the given class
2557 @param cls The class name
2558 """
2559 fn = "void\n"
2560 return fn
2561
2562
2563def instantiate_fn_ptrs(cls, ilvl, out):
2564 """
2565 Generate the C code to instantiate function pointers for a class
2566 @param cls The class name
2567 @param ilvl The base indentation level
2568 @param out The file to which to write the functions
2569 """
2570 for m_name in of_g.ordered_members[cls]:
2571 if m_name in of_g.skip_members:
2572 continue
2573 out.write(" " * ilvl + "obj->%s_get = %s_%s_get;\n" %
2574 (m_name, cls, m_name))
2575 out.write(" " * ilvl + "obj->%s_set = %s_%s_set;\n" %
2576 (m_name, cls, m_name))
2577
2578################################################################
2579# Routines to generate the body of new/delete functions
2580################################################################
2581
2582def gen_init_fn_body(cls, out):
2583 """
2584 Generate function body for init function
2585 @param cls The class name for the function
2586 @param out The file to which to write
2587 """
2588 if cls in type_maps.inheritance_map:
2589 param = "obj_p"
2590 else:
2591 param = "obj"
2592
2593 out.write("""
2594/**
2595 * Initialize an object of type %(cls)s.
2596 *
2597 * @param obj Pointer to the object to initialize
2598 * @param version The wire version to use for the object
2599 * @param bytes How many bytes in the object
2600 * @param clean_wire Boolean: If true, clear the wire object control struct
2601 *
2602 * If bytes < 0, then the default fixed length is used for the object
2603 *
2604 * This is a "coerce" function that sets up the pointers for the
2605 * accessors properly.
2606 *
2607 * If anything other than 0 is passed in for the buffer size, the underlying
2608 * wire buffer will have 'grow' called.
2609 */
2610
2611void
2612%(cls)s_init(%(cls)s_t *%(param)s,
2613 of_version_t version, int bytes, int clean_wire)
2614{
2615""" % dict(cls=cls, param=param))
2616
2617 # Use an extra pointer to deal with inheritance classes
2618 if cls in type_maps.inheritance_map:
2619 out.write("""\
2620 %s_header_t *obj;
2621
2622 obj = &obj_p->header; /* Need instantiable subclass */
2623""" % cls)
2624
2625 out.write("""
2626 ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
2627 if (clean_wire) {
2628 MEMSET(obj, 0, sizeof(*obj));
2629 }
2630 if (bytes < 0) {
2631 bytes = of_object_fixed_len[version][%(enum)s];
2632 }
2633 obj->version = version;
2634 obj->length = bytes;
2635 obj->object_id = %(enum)s;
2636""" % dict(cls=cls, enum=enum_name(cls)))
2637 gen_coerce_ops(out, cls)
2638
2639 out.write("""
2640 /* Grow the wire buffer */
2641 if (obj->wire_object.wbuf != NULL) {
2642 int tot_bytes;
2643
2644 tot_bytes = bytes + obj->wire_object.obj_offset;
2645 of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
2646 }
2647}
2648
2649""")
2650
2651## @fixme This should also be updated once there is a map from
2652# class instance to wire length/type accessors
2653def gen_wire_push_fn(cls, out):
2654 """
2655 Generate the calls to push values into the wire buffer
2656 """
2657 if type_maps.class_is_virtual(cls):
2658 print "Push fn gen called for virtual class " + cls
2659 return
2660
2661 out.write("""
2662/**
2663 * Helper function to push values into the wire buffer
2664 */
2665static inline int
2666%(cls)s_push_wire_values(%(cls)s_t *obj)
2667{
2668""" % dict(cls=cls))
2669
2670 if loxi_utils.class_is_message(cls):
2671 out.write("""
2672 /* Message obj; push version, length and type to wire */
2673 of_message_t msg;
2674
2675 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
2676 of_message_version_set(msg, obj->version);
2677 of_message_length_set(msg, obj->length);
2678 OF_TRY(of_wire_message_object_id_set(OF_OBJECT_TO_WBUF(obj),
2679 %(name)s));
2680 }
2681""" % dict(name = enum_name(cls)))
2682
2683 for version in of_g.of_version_range:
2684 if type_maps.class_is_extension(cls, version):
2685 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
2686 subtype = type_maps.extension_message_to_subtype(cls, version)
2687 if subtype is None or exp_name is None:
2688 print "Error in mapping extension message"
2689 print cls, version
2690 sys.exit(1)
2691 out.write("""
2692 if (obj->version == %(version)s) {
2693 of_message_experimenter_id_set(OF_OBJECT_TO_MESSAGE(obj),
2694 %(exp_name)s);
2695 of_message_experimenter_subtype_set(OF_OBJECT_TO_MESSAGE(obj),
2696 %(subtype)s);
2697 }
2698""" % dict(exp_name=exp_name, version=of_g.wire_ver_map[version],
2699 subtype=str(subtype)))
2700
2701 else: # Not a message
2702 if loxi_utils.class_is_tlv16(cls):
2703 out.write("""
2704 /* TLV obj; set length and type */
2705 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
2706 of_tlv16_wire_object_id_set((of_object_t *)obj,
2707 %(enum)s);
2708""" % dict(enum=enum_name(cls)))
2709 # Some tlv16 types may be extensions requiring more work
2710 if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
2711 "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
2712 "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl"]:
2713 out.write("""
2714 /* Extended TLV obj; Call specific accessor */
2715 of_extension_object_id_set(obj, %(enum)s);
2716""" % dict(cls=cls, enum=enum_name(cls)))
2717
2718
2719 if loxi_utils.class_is_oxm(cls):
2720 out.write("""\
2721 /* OXM obj; set length and type */
2722 of_oxm_wire_length_set((of_object_t *)obj, obj->length);
2723 of_oxm_wire_object_id_set((of_object_t *)obj, %(enum)s);
2724""" % dict(enum=enum_name(cls)))
2725 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2726 out.write("""
2727 obj->wire_length_set((of_object_t *)obj, obj->length);
2728""")
2729
2730 if cls == "of_meter_stats":
2731 out.write("""
2732 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2733""" % dict(enum=enum_name(cls)))
2734
2735 out.write("""
2736 return OF_ERROR_NONE;
2737}
2738""")
2739
2740def gen_new_fn_body(cls, out):
2741 """
2742 Generate function body for new function
2743 @param cls The class name for the function
2744 @param out The file to which to write
2745 """
2746
2747 out.write("""
2748/**
2749 * \\defgroup %(cls)s %(cls)s
2750 */
2751""" % dict(cls=cls))
2752
2753 if not type_maps.class_is_virtual(cls):
2754 gen_wire_push_fn(cls, out)
2755
2756 out.write("""
2757/**
2758 * Create a new %(cls)s object
2759 *
2760 * @param version The wire version to use for the object
2761 * @return Pointer to the newly create object or NULL on error
2762 *
2763 * Initializes the new object with it's default fixed length associating
2764 * a new underlying wire buffer.
2765 *
2766 * Use new_from_message to bind an existing message to a message object,
2767 * or a _get function for non-message objects.
2768 *
2769 * \\ingroup %(cls)s
2770 */
2771
2772%(cls)s_t *
2773%(cls)s_new_(of_version_t version)
2774{
2775 %(cls)s_t *obj;
2776 int bytes;
2777
2778 bytes = of_object_fixed_len[version][%(enum)s];
2779
2780 /* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
2781 if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
2782 return NULL;
2783 }
2784
2785 %(cls)s_init(obj, version, bytes, 0);
2786""" % dict(cls=cls, enum=enum_name(cls)))
2787 if not type_maps.class_is_virtual(cls):
2788 out.write("""
2789 if (%(cls)s_push_wire_values(obj) < 0) {
2790 FREE(obj);
2791 return NULL;
2792 }
2793""" % dict(cls=cls))
2794
2795 match_offset = v3_match_offset_get(cls)
2796 if match_offset >= 0:
2797 # Init length field for match object
2798 out.write("""
2799 /* Initialize match TLV for 1.2 */
2800 /* FIXME: Check 1.3 below */
2801 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2802 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2803 }
2804""" % dict(match_offset=match_offset))
2805 out.write("""
2806 return obj;
2807}
2808
2809#if defined(OF_OBJECT_TRACKING)
2810
2811/*
2812 * Tracking objects. Call the new function and then record location
2813 */
2814
2815%(cls)s_t *
2816%(cls)s_new_tracking(of_version_t version,
2817 const char *file, int line)
2818{
2819 %(cls)s_t *obj;
2820
2821 obj = %(cls)s_new_(version);
2822 of_object_track((of_object_t *)obj, file, line);
2823
2824 return obj;
2825}
2826#endif
2827""" % dict(cls=cls))
2828
2829
2830def gen_from_message_fn_body(cls, out):
2831 """
2832 Generate function body for from_message function
2833 @param cls The class name for the function
2834 @param out The file to which to write
2835 """
2836 out.write("""
2837/**
2838 * Create a new %(cls)s object and bind it to an existing message
2839 *
2840 * @param msg The message to bind the new object to
2841 * @return Pointer to the newly create object or NULL on error
2842 *
2843 * \ingroup %(cls)s
2844 */
2845
2846%(cls)s_t *
2847%(cls)s_new_from_message_(of_message_t msg)
2848{
2849 %(cls)s_t *obj = NULL;
2850 of_version_t version;
2851 int length;
2852
2853 if (msg == NULL) return NULL;
2854
2855 version = of_message_version_get(msg);
2856 if (!OF_VERSION_OKAY(version)) return NULL;
2857
2858 length = of_message_length_get(msg);
2859
2860 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2861 return NULL;
2862 }
2863
2864 %(cls)s_init(obj, version, 0, 0);
2865
2866 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2867 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2868 FREE(obj);
2869 return NULL;
2870 }
2871 obj->length = length;
2872 obj->version = version;
2873
2874 return obj;
2875}
2876
2877#if defined(OF_OBJECT_TRACKING)
2878
2879/*
2880 * Tracking objects. Call the new function and then record location
2881 */
2882
2883%(cls)s_t *
2884%(cls)s_new_from_message_tracking(of_message_t msg,
2885 const char *file, int line)
2886{
2887 %(cls)s_t *obj;
2888
2889 obj = %(cls)s_new_from_message_(msg);
2890 of_object_track((of_object_t *)obj, file, line);
2891
2892 return obj;
2893}
2894#endif
2895""" % dict(cls=cls))
2896
2897
2898################################################################
2899# Now the top level generator functions
2900################################################################
2901
2902def gen_new_function_declarations(out):
2903 """
2904 Gerenate the header file declarations for new operators for all classes
2905 @param out The file to which to write the decs
2906 """
2907
2908 out.write("""
2909/****************************************************************
2910 *
2911 * New operator declarations
2912 *
2913 * _new: Create a new object for writing; includes init
2914 * _new_from_message: Create a new instance of the object and bind the
2915 * message data to the object
2916 * _init: Initialize and optionally allocate buffer space for an
2917 * automatic instance
2918 *
2919 * _new and _from_message require a delete operation to be called
2920 * on the object.
2921 *
2922 ****************************************************************/
2923""")
2924 out.write("""
2925/*
2926 * If object tracking is enabled, map "new" and "new from msg"
2927 * calls to tracking versions; otherwise, directly to internal
2928 * versions of fns which have the same name but end in _.
2929 */
2930
2931#if defined(OF_OBJECT_TRACKING)
2932""")
2933 for cls in of_g.standard_class_order:
2934 out.write("""
2935extern %(cls)s_t *
2936 %(cls)s_new_tracking(of_version_t version,
2937 const char *file, int line);
2938#define %(cls)s_new(version) \\
2939 %(cls)s_new_tracking(version, \\
2940 __FILE__, __LINE__)
2941""" % dict(cls=cls))
2942 if loxi_utils.class_is_message(cls):
2943 out.write("""extern %(cls)s_t *
2944 %(cls)s_new_from_message_tracking(of_message_t msg,
2945 const char *file, int line);
2946#define %(cls)s_new_from_message(msg) \\
2947 %(cls)s_new_from_message_tracking(msg, \\
2948 __FILE__, __LINE__)
2949""" % dict(cls=cls))
2950
2951 out.write("""
2952#else /* No object tracking */
2953""")
2954 for cls in of_g.standard_class_order:
2955 out.write("""
2956#define %(cls)s_new(version) \\
2957 %(cls)s_new_(version)
2958""" % dict(cls=cls))
2959 if loxi_utils.class_is_message(cls):
2960 out.write("""#define %(cls)s_new_from_message(msg) \\
2961 %(cls)s_new_from_message_(msg)
2962""" % dict(cls=cls))
2963
2964 out.write("""
2965#endif /* Object tracking */
2966""")
2967
2968 for cls in of_g.standard_class_order:
2969 out.write("""
2970extern %(cls)s_t *
2971 %(cls)s_new_(of_version_t version);
2972""" % dict(cls=cls))
2973 if loxi_utils.class_is_message(cls):
2974 out.write("""extern %(cls)s_t *
2975 %(cls)s_new_from_message_(of_message_t msg);
2976""" % dict(cls=cls))
2977 out.write("""extern void %(cls)s_init(
2978 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2979""" % dict(cls=cls))
2980
2981 out.write("""
2982/****************************************************************
2983 *
2984 * Delete operator static inline definitions.
2985 * These are here for type checking purposes only
2986 *
2987 ****************************************************************/
2988""")
2989 for cls in of_g.standard_class_order:
2990# if cls in type_maps.inheritance_map:
2991# continue
2992 out.write("""
2993/**
2994 * Delete an object of type %(cls)s_t
2995 * @param obj An instance of type %(cls)s_t
2996 *
2997 * \ingroup %(cls)s
2998 */
2999static inline void
3000%(cls)s_delete(%(cls)s_t *obj) {
3001 of_object_delete((of_object_t *)(obj));
3002}
3003""" % dict(cls=cls))
3004
3005 out.write("""
3006typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
3007 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07003008extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07003009""")
3010
3011 out.write("""
3012/****************************************************************
3013 *
3014 * Function pointer initialization functions
3015 * These are part of the "coerce" type casting for objects
3016 *
3017 ****************************************************************/
3018""")
3019
3020#
3021# @fixme Not clear that these should all be set for virtual fns
3022#
3023# @fixme Clean up. should have a (language specific) map from class
3024# to length and type get/set functions
3025#
3026
3027def gen_coerce_ops(out, cls):
3028 out.write("""
3029 /* Set up the object's function pointers */
3030""")
3031
3032 if loxi_utils.class_is_message(cls):
3033 out.write("""
3034 obj->wire_length_get = of_object_message_wire_length_get;
3035 obj->wire_length_set = of_object_message_wire_length_set;
3036""")
3037 else:
3038 if loxi_utils.class_is_tlv16(cls):
3039 if not (cls in type_maps.inheritance_map): # Don't set for super
3040 out.write("""
3041 obj->wire_length_set = of_tlv16_wire_length_set;
3042 obj->wire_type_set = of_tlv16_wire_object_id_set;\
3043""")
3044 out.write("""
3045 obj->wire_length_get = of_tlv16_wire_length_get;
3046""")
3047 if loxi_utils.class_is_action(cls):
3048 out.write("""
3049 obj->wire_type_get = of_action_wire_object_id_get;
3050""")
3051 if loxi_utils.class_is_action_id(cls):
3052 out.write("""
3053 obj->wire_type_get = of_action_id_wire_object_id_get;
3054""")
3055 if loxi_utils.class_is_instruction(cls):
3056 out.write("""
3057 obj->wire_type_get = of_instruction_wire_object_id_get;
3058""")
3059 if loxi_utils.class_is_queue_prop(cls):
3060 out.write("""
3061 obj->wire_type_get = of_queue_prop_wire_object_id_get;
3062""")
3063 if loxi_utils.class_is_table_feature_prop(cls):
3064 out.write("""
3065 obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
3066""")
3067 if loxi_utils.class_is_meter_band(cls):
3068 out.write("""
3069 obj->wire_type_get = of_meter_band_wire_object_id_get;
3070""")
3071 if loxi_utils.class_is_hello_elem(cls):
3072 out.write("""
3073 obj->wire_type_get = of_hello_elem_wire_object_id_get;
3074""")
3075 if loxi_utils.class_is_oxm(cls):
3076 out.write("""
3077 obj->wire_length_get = of_oxm_wire_length_get;
3078 obj->wire_length_set = of_oxm_wire_length_set;
3079 obj->wire_type_get = of_oxm_wire_object_id_get;
3080 obj->wire_type_set = of_oxm_wire_object_id_set;
3081""")
3082 if loxi_utils.class_is_u16_len(cls):
3083 out.write("""
3084 obj->wire_length_get = of_u16_len_wire_length_get;
3085 obj->wire_length_set = of_u16_len_wire_length_set;
3086""")
3087 if cls == "of_packet_queue":
3088 out.write("""
3089 obj->wire_length_get = of_packet_queue_wire_length_get;
3090 obj->wire_length_set = of_packet_queue_wire_length_set;
3091""")
3092# if cls == "of_list_meter_band_stats":
3093# out.write("""
3094# obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
3095#""")
3096 if cls == "of_meter_stats":
3097 out.write("""
3098 obj->wire_length_get = of_meter_stats_wire_length_get;
3099 obj->wire_length_set = of_meter_stats_wire_length_set;
3100""")
3101
3102 if config_check("gen_fn_ptrs"):
3103 if loxi_utils.class_is_list(cls):
3104 out.write("""
3105 obj->first = %(cls)s_first;
3106 obj->next = %(cls)s_next;
3107 obj->append = %(cls)s_append;
3108 obj->append_bind = %(cls)s_append_bind;
3109""" % dict(cls=cls))
3110 else:
3111 instantiate_fn_ptrs(cls, 4, out)
3112
3113def gen_new_function_definitions(out):
3114 """
3115 Generate the new operator for all classes
3116
3117 @param out The file to which to write the functions
3118 """
3119
3120 out.write("\n/* New operators for each message class */\n")
3121 for cls in of_g.standard_class_order:
3122 out.write("\n/* New operators for %s */\n" % cls)
3123 gen_new_fn_body(cls, out)
3124 gen_init_fn_body(cls, out)
3125 if loxi_utils.class_is_message(cls):
3126 gen_from_message_fn_body(cls, out)
3127
3128def gen_init_map(out):
3129 """
3130 Generate map from object ID to type coerce function
3131 """
3132 out.write("""
3133/**
3134 * Map from object ID to type coerce function
3135 */
Rich Laneb157b0f2013-03-27 13:55:28 -07003136const of_object_init_f of_object_init_map[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07003137 (of_object_init_f)NULL,
3138""")
3139 count = 1
3140 for i, cls in enumerate(of_g.standard_class_order):
3141 if count != of_g.unified[cls]["object_id"]:
3142 print "Error in class mapping: object IDs not sequential"
3143 print cls, count, of_g.unified[cls]["object_id"]
3144 sys.exit(1)
3145 s = "(of_object_init_f)%s_init" % cls
3146 if cls in type_maps.inheritance_map:
3147 s = "(of_object_init_f)%s_header_init" % cls
3148 if i < len(of_g.standard_class_order) - 1:
3149 s += ","
3150 out.write(" %-65s /* %d */\n" % (s, count))
3151 count += 1
3152 out.write("};\n")
3153
3154"""
3155Document generation functions
3156
3157The main reason this is here is to generate documentation per
3158accessor that indicates the versions that support the interface.
3159"""
3160
3161
3162def gen_accessor_doc(out, name):
3163 """
3164 Generate documentation for each accessor function that indicates
3165 the versions supporting the accessor.
3166 """
3167
3168 common_top_matter(out, name)
3169
3170 out.write("/* DOCUMENTATION ONLY */\n")
3171
3172 for cls in of_g.standard_class_order:
3173 if cls in type_maps.inheritance_map:
3174 pass # Check this
3175
3176 out.write("""
3177/**
3178 * Structure for %(cls)s object. Get/set
3179 * accessors available in all versions unless noted otherwise
3180 *
3181""" % dict(cls=cls))
3182 if loxi_utils.class_is_list(cls):
3183 out.write("""\
3184 * @param first Function of type %(cls)s_first_f.
3185 * Setup a TBD class object to the first entry in the list
3186 * @param next Function of type %(cls)s_next_f.
3187 * Advance a TBD class object to the next entry in the list
3188 * @param append_bind Function of type %(cls)s_append_bind_f
3189 * Setup a TBD class object for append to the end of the current list
3190 * @param append Function of type @ref %(cls)s_append_f.
3191 * Copy an item to the end of a list
3192""" % dict(cls=cls))
3193
3194 for m_name in of_g.ordered_members[cls]:
3195 if m_name in of_g.skip_members:
3196 continue
3197 ver_type_map = field_ver_get(cls, m_name)
3198 (m_type, get_rv) = get_acc_rv(cls, m_name)
3199 if len(ver_type_map) == 3:
3200 # ver_string = "Available in all versions"
3201 ver_string = ""
3202 else:
3203 ver_string = "("
3204 for ver in sorted(ver_type_map):
3205 ver_string += " " + of_g.short_version_names[ver]
3206 ver_string += ")."
3207
3208 f_name = acc_name(cls, m_name)
3209 out.write("""\
3210 * @param %(m_name)s_get/set %(ver_string)s
3211 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
3212 * are of type %(f_name)s_get_f and _set_f.
3213 *
3214""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
3215
3216 out.write("""\
3217 */
3218typedef struct %(cls)s_s %(cls)s_t;
3219""" % dict(cls=cls))
3220
3221 out.write("#endif /* _LOCI_DOC_H_ */\n")
3222
3223################################################################
3224#
3225# For fun, here are some unified, traditional C structure representation
3226#
3227################################################################
3228
3229def gen_cof_to_wire(out):
3230 pass
3231
3232def gen_wire_to_cof(out):
3233 pass
3234
3235def gen_cof_instance(out, cls):
3236 out.write("struct c%s_s {\n" % cls)
3237 for m in of_g.ordered_members[cls]:
3238 if m in of_g.skip_members:
3239 continue
3240 entry = of_g.unified[cls]["union"][m]
3241 cof_type = type_to_cof_type(entry["m_type"])
3242 out.write(" %-20s %s;\n" % (cof_type, m))
3243 out.write("};\n\n");
3244
3245def gen_cof_structs(out):
3246 """
3247 Generate non-version specific (common) representation of structures
3248
3249 @param out The file to which to write the functions
3250 """
3251
3252 out.write("\n/* Common, unified OpenFlow structure representations */\n")
3253 for cls in of_g.standard_class_order:
3254 if cls in type_maps.inheritance_map:
3255 continue
3256 gen_cof_instance(out, cls)
3257
3258################################################################
3259#
3260# Generate code samples for applications.
3261#
3262################################################################
3263
3264def gen_code_samples(out, name):
3265 out.write("""
3266#if 0 /* Do not compile in */
3267/**
3268 * @file %(name)s
3269 *
3270 * These are code samples for inclusion in other components
3271 */
3272
3273""" % dict(name=name))
3274
3275 gen_jump_table_template(out)
3276 # These are messages that a switch might expect.
3277 msg_list = ["of_echo_request",
3278 "of_hello",
3279 "of_packet_in",
3280 "of_packet_out",
3281 "of_port_mod",
3282 "of_port_stats_request",
3283 "of_queue_get_config_request",
3284 "of_queue_stats_request",
3285 "of_flow_add",
3286 "of_flow_modify",
3287 "of_flow_modify_strict",
3288 "of_flow_delete",
3289 "of_flow_delete_strict",
3290 "of_get_config_request",
3291 "of_flow_stats_request",
3292 "of_barrier_request",
3293 "of_echo_reply",
3294 "of_aggregate_stats_request",
3295 "of_desc_stats_request",
3296 "of_table_stats_request",
3297 "of_features_request",
3298 "of_table_mod",
3299 "of_set_config",
3300 "of_experimenter",
3301 "of_experimenter_stats_request",
3302 "of_group_desc_stats_request",
3303 "of_group_features_stats_request",
3304 "of_role_request"]
3305
3306 gen_message_handler_templates(out, msgs=msg_list)
3307
3308 out.write("""
3309#endif
3310""")
3311
3312def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
3313 cxn_type="ls_cxn_handle_t",
3314 unhandled="unhandled_message"):
3315 """
3316 Generate a template for a jump table.
3317 @param out The file to which to write the functions
3318 """
3319 out.write("""
3320/*
3321 * Simple jump table definition for message handling
3322 */
3323typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
3324typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
3325
3326/* Jump table template for message objects */
3327extern msg_jump_table_t jump_table;
3328
3329/* C-code template */
3330msg_jump_table_t jump_table = {
3331 %(unhandled)s, /* OF_OBJECT; place holder for generic object */
3332""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3333 count = 0
3334 fn_name = unhandled
3335 for cls in of_g.ordered_messages:
3336 comma = ","
3337 count += 1
3338 if count == len(of_g.ordered_messages):
3339 comma = " "
3340 if not all_unhandled:
3341 fn_name = "%s_handler" % cls[3:]
3342 out.write(" %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
3343
3344 out.write("};\n")
3345
3346def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
3347 cxn_type="ls_cxn_handle_t",
3348 unhandled="unhandled_message"):
3349 out.write("""
3350/*
3351 * Simple switch statement for message handling
3352 */
3353
3354 switch (obj->object_id):
3355""")
3356 fn_name = unhandled
3357 for cls in of_g.ordered_messages:
3358 if not all_unhandled:
3359 fn_name = "%s_handler" % cls[3:]
3360 out.write("""
3361 case %(enum)s:
3362 rv = %(fn_name)s(cxn, obj);
3363 break;
3364""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
3365 out.write("""
3366 default:
3367 rv = LS_ERROR_PARAM;
3368 break;
3369 }
3370
3371 TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
3372
3373 return rv;
3374""")
3375
3376
3377def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
3378 unhandled="unhandled_message", msgs=None):
3379 gen_jump_table_template(out, False, cxn_type)
3380 out.write("""
3381/**
3382 * Function for unhandled message
3383 */
3384static int
3385unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
3386{
3387 (void)cxn;
3388 (void)obj;
3389 TRACE("Unhandled message %%p. Object id %%d", obj, obj->object_id);
3390
3391 return LS_ERROR_UNAVAIL;
3392}
3393""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3394
3395 if not msgs:
3396 msgs = of_g.ordered_messages
3397 for cls in msgs:
3398 out.write("""
3399/**
3400 * Handle a %(s_cls)s message
3401 * @param cxn Connection handler for the owning connection
3402 * @param _obj Generic type object for the message to be coerced
3403 * @returns Error code
3404 */
3405
3406static int
3407%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
3408{
3409 %(cls)s_t *obj;
3410
3411 TRACE("Handling %(cls)s message: %%p.", obj);
3412 obj = (%(cls)s_t *)_obj;
3413
3414 /* Handle object of type %(cls)s_t */
3415
3416 return LS_ERROR_NONE;
3417}
3418""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
3419 gen_message_switch_stmt_tmeplate(out, False, cxn_type)
3420
3421def gen_setup_from_add_fns(out):
3422 """
3423 Generate functions that setup up objects based on an add
3424
3425 Okay, this is getting out of hand. We need to refactor the code
3426 so that this can be done without so much pain.
3427 """
3428 out.write("""
3429
3430/* Flow stats entry setup for all versions */
3431
3432static int
3433flow_stats_entry_setup_from_flow_add_common(of_flow_stats_entry_t *obj,
3434 of_flow_add_t *flow_add,
3435 of_object_t *effects,
3436 int entry_match_offset,
3437 int add_match_offset)
3438{
3439 of_list_action_t actions;
3440 int entry_len, add_len;
3441 of_wire_buffer_t *wbuf;
3442 int abs_offset;
3443 int delta;
3444 uint16_t val16;
3445 uint64_t cookie;
3446 of_octets_t match_octets;
3447
3448 /* Effects may come from different places */
3449 if (effects != NULL) {
3450 OF_TRY(of_flow_stats_entry_actions_set(obj,
3451 (of_list_action_t *)effects));
3452 } else {
3453 of_flow_add_actions_bind(flow_add, &actions);
3454 OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
3455 }
3456
3457 /* Transfer the match underlying object from add to stats entry */
3458 wbuf = OF_OBJECT_TO_WBUF(obj);
3459 entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset);
3460 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3461
3462 match_octets.bytes = add_len;
3463 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3464
3465 /* Copy data into flow entry */
3466 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, entry_match_offset);
3467 of_wire_buffer_replace_data(wbuf, abs_offset, entry_len,
3468 match_octets.data, add_len);
3469
3470 /* Not scalar, update lengths if needed */
3471 delta = add_len - entry_len;
3472 if (delta != 0) {
3473 /* Update parent(s) */
3474 of_object_parent_length_update((of_object_t *)obj, delta);
3475 }
3476
3477 of_flow_add_cookie_get(flow_add, &cookie);
3478 of_flow_stats_entry_cookie_set(obj, cookie);
3479
3480 of_flow_add_priority_get(flow_add, &val16);
3481 of_flow_stats_entry_priority_set(obj, val16);
3482
3483 of_flow_add_idle_timeout_get(flow_add, &val16);
3484 of_flow_stats_entry_idle_timeout_set(obj, val16);
3485
3486 of_flow_add_hard_timeout_get(flow_add, &val16);
3487 of_flow_stats_entry_hard_timeout_set(obj, val16);
3488
3489 return OF_ERROR_NONE;
3490}
3491
3492/* Flow removed setup for all versions */
3493
3494static int
3495flow_removed_setup_from_flow_add_common(of_flow_removed_t *obj,
3496 of_flow_add_t *flow_add,
3497 int removed_match_offset,
3498 int add_match_offset)
3499{
3500 int add_len, removed_len;
3501 of_wire_buffer_t *wbuf;
3502 int abs_offset;
3503 int delta;
3504 uint16_t val16;
3505 uint64_t cookie;
3506 of_octets_t match_octets;
3507
3508 /* Transfer the match underlying object from add to removed obj */
3509 wbuf = OF_OBJECT_TO_WBUF(obj);
3510 removed_len = _WIRE_MATCH_PADDED_LEN(obj, removed_match_offset);
3511 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3512
3513 match_octets.bytes = add_len;
3514 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3515
3516 /* Copy data into flow removed */
3517 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, removed_match_offset);
3518 of_wire_buffer_replace_data(wbuf, abs_offset, removed_len,
3519 match_octets.data, add_len);
3520
3521 /* Not scalar, update lengths if needed */
3522 delta = add_len - removed_len;
3523 if (delta != 0) {
3524 /* Update parent(s) */
3525 of_object_parent_length_update((of_object_t *)obj, delta);
3526 }
3527
3528 of_flow_add_cookie_get(flow_add, &cookie);
3529 of_flow_removed_cookie_set(obj, cookie);
3530
3531 of_flow_add_priority_get(flow_add, &val16);
3532 of_flow_removed_priority_set(obj, val16);
3533
3534 of_flow_add_idle_timeout_get(flow_add, &val16);
3535 of_flow_removed_idle_timeout_set(obj, val16);
3536
3537 if (obj->version >= OF_VERSION_1_2) {
3538 of_flow_add_hard_timeout_get(flow_add, &val16);
3539 of_flow_removed_hard_timeout_set(obj, val16);
3540 }
3541
3542 return OF_ERROR_NONE;
3543}
3544
3545/* Set up a flow removed message from the original add */
3546
3547int
3548of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
3549 of_flow_add_t *flow_add)
3550{
3551 switch (obj->version) {
3552 case OF_VERSION_1_0:
3553 return flow_removed_setup_from_flow_add_common(obj, flow_add,
3554 8, 8);
3555 break;
3556 case OF_VERSION_1_1:
3557 case OF_VERSION_1_2:
3558 case OF_VERSION_1_3:
3559 return flow_removed_setup_from_flow_add_common(obj, flow_add,
3560 48, 48);
3561 break;
3562 default:
3563 return OF_ERROR_VERSION;
3564 break;
3565 }
3566
3567 return OF_ERROR_NONE;
3568}
3569
3570
3571/* Set up a packet in message from the original add */
3572
3573int
3574of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
3575 of_flow_add_t *flow_add)
3576{
3577 int add_len, pkt_in_len;
3578 of_wire_buffer_t *wbuf;
3579 int abs_offset;
3580 int delta;
3581 const int pkt_in_match_offset = 16;
3582 const int add_match_offset = 48;
3583 of_octets_t match_octets;
3584
3585 if (obj->version < OF_VERSION_1_2) {
3586 /* Nothing to be done before OF 1.2 */
3587 return OF_ERROR_NONE;
3588 }
3589
3590 /* Transfer match struct from flow add to packet in object */
3591 wbuf = OF_OBJECT_TO_WBUF(obj);
3592 pkt_in_len = _WIRE_MATCH_PADDED_LEN(obj, pkt_in_match_offset);
3593 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3594
3595 match_octets.bytes = add_len;
3596 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3597
3598 /* Copy data into pkt_in msg */
3599 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, pkt_in_match_offset);
3600 of_wire_buffer_replace_data(wbuf, abs_offset, pkt_in_len,
3601 match_octets.data, add_len);
3602
3603 /* Not scalar, update lengths if needed */
3604 delta = add_len - pkt_in_len;
3605 if (delta != 0) {
3606 /* Update parent(s) */
3607 of_object_parent_length_update((of_object_t *)obj, delta);
3608 }
3609
3610 return OF_ERROR_NONE;
3611}
3612
3613/* Set up a stats entry from the original add */
3614
3615int
3616of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
3617 of_flow_add_t *flow_add,
3618 of_object_t *effects)
3619{
3620 switch (obj->version) {
3621 case OF_VERSION_1_0:
3622 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
3623 effects, 4, 8);
3624 break;
3625 case OF_VERSION_1_1:
3626 case OF_VERSION_1_2:
3627 case OF_VERSION_1_3:
3628 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
3629 effects, 48, 48);
3630 break;
3631 default:
3632 return OF_ERROR_VERSION;
3633 }
3634
3635 return OF_ERROR_NONE;
3636}
3637""")