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