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