blob: df9d9da328e4514cea59e410e55ae52684d5d2a8 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@file code_gen.py
30Code generation functions for LOCI
31"""
32
33import sys
34import of_g
35import c_match
36from generic_utils import *
37import c_gen.c_type_maps as c_type_maps
38import loxi_front_end.type_maps as type_maps
39import loxi_front_end.flags as flags
40import loxi_utils.loxi_utils as loxi_utils
41import loxi_front_end.identifiers as identifiers
42
43# 'property' is for queues. Could be trouble
44
45
46################################################################
47#
48# Misc helper functions
49#
50################################################################
51
52def h_file_to_define(name):
53 """
54 Convert a .h file name to the define used for the header
55 """
56 h_name = name[:-2].upper()
57 h_name = "_" + h_name + "_H_"
58 return h_name
59
60def enum_name(cls):
61 """
62 Return the name used for an enum identifier for the given class
63 @param cls The class name
64 """
65 return loxi_utils.enum_name(cls)
66
67def member_returns_val(cls, m_name):
68 """
69 Should get accessor return a value rather than void
70 @param cls The class name
71 @param m_name The member name
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"
789
790""")
791 gen_object_enum_str(out)
792 gen_len_offset_macros(out)
793 gen_obj_id_macros(out)
794 if config_check("gen_unified_fns"):
795 gen_accessor_definitions(out)
796 gen_new_function_definitions(out)
797 gen_init_map(out)
798 out.write("\n/* This code should be broken out to a different file */\n")
799 gen_setup_from_add_fns(out)
800
801def type_data_c_gen(out, name):
802 common_top_matter(out, name)
803 c_type_maps.gen_type_maps(out)
804 c_type_maps.gen_length_array(out)
Rich Lanef70be942013-07-18 13:33:14 -0700805 c_type_maps.gen_extra_length_array(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700806
807################################################################
808# Top Matter
809################################################################
810
811def common_top_matter(out, name):
812 loxi_utils.gen_c_copy_license(out)
813 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700814
Rich Lanea06d0c32013-03-25 08:52:03 -0700815/****************************************************************
816 * File: %s
817 *
818 * DO NOT EDIT
819 *
820 * This file is automatically generated
821 *
822 ****************************************************************/
823
824""" % name)
825
826 if name[-2:] == ".h":
827 out.write("""
828#if !defined(%(h)s)
829#define %(h)s
830
831""" % dict(h=h_file_to_define(name)))
832
833def base_h_content(out):
834 """
835 Generate base header file content
836
837 @param out The output file object
838 """
839
840 # @fixme Supported version should be generated based on input to LoxiGen
841
842 out.write("""
843/*
844 * Base OpenFlow definitions. These depend only on standard C headers
845 */
846#include <string.h>
847#include <stdint.h>
848
849/* g++ requires this to pick up PRI, etc.
850 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
851 */
852#if !defined(__STDC_FORMAT_MACROS)
853#define __STDC_FORMAT_MACROS
854#endif
855#include <inttypes.h>
856
857#include <stdlib.h>
858#include <assert.h>
859#include <loci/loci_idents.h>
860
861/**
862 * Macro to enable debugging for LOCI.
863 *
864 * This enables debug output to stdout.
865 */
866#define OF_DEBUG_ENABLE
867
868#if defined(OF_DEBUG_ENABLE)
869#include <stdio.h> /* Currently for debugging */
870#define FIXME(str) do { \\
871 fprintf(stderr, "%s\\n", str); \\
872 exit(1); \\
873 } while (0)
874#define debug printf
875#else
876#define FIXME(str)
877#define debug(str, ...)
878#endif /* OF_DEBUG_ENABLE */
879
880/**
881 * The type of a function used by the LOCI dump/show functions to
882 * output text. Essentially the same signature as fprintf. May
883 * be called many times per invocation of e.g. of_object_show().
884 */
885typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
886
887/**
888 * Check if a version is supported
889 */
890#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
891
892""")
893 gen_version_enum(out)
894 out.write("\n")
895
896 # for c_name in of_g.ofp_constants:
897 # val = str(of_g.ofp_constants[c_name])
898 # out.write("#define %s %s\n" % (c_name, val))
899 # out.write("\n")
900
901 out.write("""
902typedef enum of_error_codes_e {
903 OF_ERROR_NONE = 0,
904 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
905 OF_ERROR_PARAM = -2, /* Bad parameter */
906 OF_ERROR_VERSION = -3, /* Version not supported */
907 OF_ERROR_RANGE = -4, /* End of list indication */
908 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
909 OF_ERROR_PARSE = -6, /* Error in parsing data */
910 OF_ERROR_INIT = -7, /* Uninitialized data */
911 OF_ERROR_UNKNOWN = -8 /* Unknown error */
912} of_error_codes_t;
913
914#define OF_ERROR_STRINGS "none", \\
915 "resource", \\
916 "parameter", \\
917 "version", \\
918 "range", \\
919 "incompatible", \\
920 "parse", \\
921 "init", \\
922 "unknown"
923
Rich Laneb157b0f2013-03-27 13:55:28 -0700924extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700925
Rich Lane53757732013-02-23 17:00:10 -0800926#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700927/* #define ASSERT(val) assert(val) */
928#define FORCE_FAULT *(volatile int *)0 = 1
929#define ASSERT(val) if (!(val)) \\
930 fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
931 FORCE_FAULT
Rich Lane53757732013-02-23 17:00:10 -0800932#else
933#define ASSERT(val)
934#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700935
936/*
937 * Some LOCI object accessors can fail, and it's easy to forget to check.
938 * On certain compilers we can trigger a warning if the error code
939 * is ignored.
940 */
941#ifndef DISABLE_WARN_UNUSED_RESULT
942#ifdef __GNUC__
943#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
944#else
945#define WARN_UNUSED_RESULT
946#endif
947#else
948#define WARN_UNUSED_RESULT
949#endif
950
951typedef union of_generic_u of_generic_t;
952typedef struct of_object_s of_object_t;
953
954/* Define ipv4 address as uint32 */
955typedef uint32_t of_ipv4_t;
956
957/* Table ID is the OF standard uint8 */
958typedef uint8_t of_table_id_t;
959
960#define OF_MAC_ADDR_BYTES 6
961typedef struct of_mac_addr_s {
962 uint8_t addr[OF_MAC_ADDR_BYTES];
963} of_mac_addr_t;
964
965#define OF_IPV6_BYTES 16
966typedef struct of_ipv6_s {
967 uint8_t addr[OF_IPV6_BYTES];
968} of_ipv6_t;
969
970extern const of_mac_addr_t of_mac_addr_all_ones;
971extern const of_mac_addr_t of_mac_addr_all_zeros;
972
973extern const of_ipv6_t of_ipv6_all_ones;
974extern const of_ipv6_t of_ipv6_all_zeros;
975
976/**
977 * Generic zero and all-ones values of size 16 bytes.
978 *
979 * IPv6 is longest data type we worry about for comparisons
980 */
981#define of_all_zero_value of_ipv6_all_zeros
982#define of_all_ones_value of_ipv6_all_ones
983
984/**
985 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
986 */
987#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
988 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
989#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
990 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
991
992/* The octets object is a struct holding pointer and length */
993typedef struct of_octets_s {
994 uint8_t *data;
995 int bytes;
996} of_octets_t;
997
998/* Macro to convert an octet object to a pointer; currently trivial */
999#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
1000#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
1001#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
1002#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
1003
1004/* Currently these are categorized as scalars */
1005typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
1006typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
1007typedef char of_desc_str_t[OF_DESC_STR_LEN];
1008typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
1009
1010/* These are types which change across versions. */
1011typedef uint32_t of_port_no_t;
1012typedef uint16_t of_fm_cmd_t;
1013typedef uint64_t of_wc_bmap_t;
1014typedef uint64_t of_match_bmap_t;
1015
1016#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
1017#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
1018#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
1019#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
1020#define MALLOC(bytes) malloc(bytes)
1021#define FREE(ptr) free(ptr)
1022
1023/** Try an operation and return on failure. */
1024#define OF_TRY(op) do { \\
1025 int _rv; \\
1026 if ((_rv = (op)) < 0) { \\
1027 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1028 return _rv; \\
1029 } \\
1030 } while (0)
1031
1032/* The extent of an OF match object is determined by its length field, but
1033 * aligned to 8 bytes
1034 */
1035
1036#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
1037
1038#if __BYTE_ORDER == __BIG_ENDIAN
1039#define U16_NTOH(val) (val)
1040#define U32_NTOH(val) (val)
1041#define U64_NTOH(val) (val)
1042#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
1043#define U16_HTON(val) (val)
1044#define U32_HTON(val) (val)
1045#define U64_HTON(val) (val)
1046#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
1047#else /* Little Endian */
1048#define U16_NTOH(val) (((val) >> 8) | ((val) << 8))
1049#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
1050 (((val) & 0x00ff0000) >> 8) | \\
1051 (((val) & 0x0000ff00) << 8) | \\
1052 (((val) & 0x000000ff) << 24))
1053#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
1054 (((val) & 0x00ff000000000000LL) >> 40) | \\
1055 (((val) & 0x0000ff0000000000LL) >> 24) | \\
1056 (((val) & 0x000000ff00000000LL) >> 8) | \\
1057 (((val) & 0x00000000ff000000LL) << 8) | \\
1058 (((val) & 0x0000000000ff0000LL) << 24) | \\
1059 (((val) & 0x000000000000ff00LL) << 40) | \\
1060 (((val) & 0x00000000000000ffLL) << 56))
1061#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
1062#define U16_HTON(val) U16_NTOH(val)
1063#define U32_HTON(val) U32_NTOH(val)
1064#define U64_HTON(val) U64_NTOH(val)
1065#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
1066#endif
1067
1068/****************************************************************
1069 *
1070 * The following are internal definitions used by the automatically
1071 * generated code. Users should not reference these definitions
1072 * as they may change between versions of this code
1073 *
1074 ****************************************************************/
1075
1076#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
1077 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
1078#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
1079#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
1080 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
1081
1082#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
1083 (FIXED_LEN + of_message_out_actions_len_get(obj))
1084
1085""")
1086
1087def external_h_top_matter(out, name):
1088 """
1089 Generate top matter for external header file
1090
1091 @param name The name of the output file
1092 @param out The output file object
1093 """
1094 common_top_matter(out, name)
1095 out.write("""
1096#include <loci/loci_base.h>
1097#include <loci/of_message.h>
1098#include <loci/of_match.h>
1099#include <loci/of_object.h>
1100#include <loci/of_wire_buf.h>
1101
1102/****************************************************************
1103 *
1104 * This file is divided into the following sections.
1105 *
1106 * A few object specific macros
1107 * Class typedefs (no struct definitions)
1108 * Per-data type accessor function typedefs
1109 * Per-class new/delete function typedefs
1110 * Per-class static delete functions
1111 * Per-class, per-member accessor declarations
1112 * Per-class structure definitions
1113 * Generic union (inheritance) definitions
1114 * Pointer set function declarations
1115 * Some special case macros
1116 *
1117 ****************************************************************/
1118""")
1119
1120def gen_top_static_functions(out):
1121 out.write("""
1122
1123#define _MAX_PARENT_ITERATIONS 4
1124/**
1125 * Iteratively update parent lengths thru hierarchy
1126 * @param obj The object whose length is being updated
1127 * @param delta The difference between the current and new lengths
1128 *
1129 * Note that this includes updating the object itself. It will
1130 * iterate thru parents.
1131 *
1132 * Assumes delta > 0.
1133 */
1134static inline void
1135of_object_parent_length_update(of_object_t *obj, int delta)
1136{
Rich Laneed79e0d2013-03-26 14:30:31 -07001137#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -07001138 int count = 0;
1139 of_wire_buffer_t *wbuf; /* For debug asserts only */
Rich Laneed79e0d2013-03-26 14:30:31 -07001140#endif
Rich Lanea06d0c32013-03-25 08:52:03 -07001141
1142 while (obj != NULL) {
1143 ASSERT(count++ < _MAX_PARENT_ITERATIONS);
1144 obj->length += delta;
1145 if (obj->wire_length_set != NULL) {
1146 obj->wire_length_set(obj, obj->length);
1147 }
Rich Laneed79e0d2013-03-26 14:30:31 -07001148#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -07001149 wbuf = obj->wire_object.wbuf;
Rich Laneed79e0d2013-03-26 14:30:31 -07001150#endif
Rich Lanea06d0c32013-03-25 08:52:03 -07001151
1152 /* Asserts for wire length checking */
1153 ASSERT(obj->length + obj->wire_object.obj_offset <=
1154 WBUF_CURRENT_BYTES(wbuf));
1155 if (obj->parent == NULL) {
1156 ASSERT(obj->length + obj->wire_object.obj_offset ==
1157 WBUF_CURRENT_BYTES(wbuf));
1158 }
1159
1160 obj = obj->parent;
1161 }
1162}
1163""")
1164
1165################################################################
1166#
1167################################################################
1168
1169def gen_version_enum(out):
1170 """
1171 Generate the enumerated type for versions in LoxiGen
1172 @param out The file object to which to write the decs
1173
1174 This just uses the wire versions for now
1175 """
1176 out.write("""
1177/**
1178 * Enumeration of OpenFlow versions
1179 *
1180 * The wire protocol numbers are currently used for values of the corresponding
1181 * version identifiers.
1182 */
1183typedef enum of_version_e {
1184 OF_VERSION_UNKNOWN = 0,
1185""")
1186
1187 is_first = True
1188 max = 0
1189 for v in of_g.wire_ver_map:
1190 if is_first:
1191 is_first = False
1192 else:
1193 out.write(",\n")
1194 if v > max:
1195 max = v
1196 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
1197
1198 out.write("""
1199} of_version_t;
1200
1201/**
1202 * @brief Use this when declaring arrays indexed by wire version
1203 */
1204#define OF_VERSION_ARRAY_MAX %d
1205""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -07001206
Rich Lanea06d0c32013-03-25 08:52:03 -07001207def gen_object_enum(out):
1208 """
1209 Generate the enumerated type for object identification in LoxiGen
1210 @param out The file object to which to write the decs
1211 """
1212 out.write("""
1213
1214/**
1215 * Enumeration of OpenFlow objects
1216 *
1217 * We enumerate the OpenFlow objects used internally. Note that some
1218 * message types are determined both by an outer type (message type like
1219 * stats_request) and an inner type (port stats). These are different
1220 * messages in ofC.
1221 *
1222 * These values are for internal use only. They will change with
1223 * different versions of ofC.
1224 */
1225
1226typedef enum of_object_id_e {
1227 /* Root object type */
1228 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
1229 OF_OBJECT = 0, /* Generic, untyped object */
1230
1231 /* OpenFlow message objects */
1232""")
1233 last = 0
1234 msg_count = 0
1235 for cls in of_g.ordered_messages:
1236 out.write(" %s = %d,\n" % (enum_name(cls),
1237 of_g.unified[cls]["object_id"]))
1238 msg_count = of_g.unified[cls]["object_id"] + 1
1239
1240 out.write("\n /* Non-message objects */\n")
1241 for cls in of_g.ordered_non_messages:
1242 out.write(" %s = %d,\n" % (enum_name(cls),
1243 of_g.unified[cls]["object_id"]))
1244 last = of_g.unified[cls]["object_id"]
1245 out.write("\n /* List objects */\n")
1246 for cls in of_g.ordered_list_objects:
1247 out.write(" %s = %d,\n" % (enum_name(cls),
1248 of_g.unified[cls]["object_id"]))
1249 last = of_g.unified[cls]["object_id"]
1250
1251 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1252 for cls in of_g.ordered_pseudo_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("""
1258 OF_OBJECT_COUNT = %d
1259} of_object_id_t;
1260
Rich Laneb157b0f2013-03-27 13:55:28 -07001261extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -07001262
1263#define OF_MESSAGE_OBJECT_COUNT %d
1264""" % ((last + 1), msg_count))
1265
1266 # Generate object type range checking for inheritance classes
1267
1268 # @fixme These should be determined algorithmicly
1269 out.write("""
1270/*
1271 * Macros to check if an object ID is within an inheritance class range
1272 */
1273""")
1274 # Alphabetical order for 'last'
1275 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
1276 of_oxm="OF_OXM_VLAN_VID_MASKED",
1277 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
1278 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
1279 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
1280 # @FIXME add meter_band ?
1281 )
1282 for cls, last in last_ids.items():
1283 out.write("""
1284#define %(enum)s_FIRST_ID (%(enum)s + 1)
1285#define %(enum)s_LAST_ID %(last)s
1286#define %(enum)s_VALID_ID(id) \\
1287 ((id) >= %(enum)s_FIRST_ID && \\
1288 (id) <= %(enum)s_LAST_ID)
1289""" % dict(enum=enum_name(cls), last=last))
1290 out.write("""
1291/**
1292 * Function to check a wire ID
1293 * @param object_id The ID to check
1294 * @param base_object_id The inheritance parent, if applicable
1295 * @returns boolean: If base_object_id is an inheritance class, check if
1296 * object_id is valid as a subclass. Otherwise return 1.
1297 *
1298 * Note: Could check that object_id == base_object_id in the
1299 * second case.
1300 */
1301static inline int
1302of_wire_id_valid(int object_id, int base_object_id) {
1303 switch (base_object_id) {
1304 case OF_ACTION:
1305 return OF_ACTION_VALID_ID(object_id);
1306 case OF_OXM:
1307 return OF_OXM_VALID_ID(object_id);
1308 case OF_QUEUE_PROP:
1309 return OF_QUEUE_PROP_VALID_ID(object_id);
1310 case OF_TABLE_FEATURE_PROP:
1311 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
1312 case OF_INSTRUCTION:
1313 return OF_INSTRUCTION_VALID_ID(object_id);
1314 default:
1315 break;
1316 }
1317 return 1;
1318}
1319""")
1320
1321def gen_object_enum_str(out):
Rich Laneb157b0f2013-03-27 13:55:28 -07001322 out.write("\nconst char *const of_object_id_str[] = {\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001323 out.write(" \"of_object\",\n")
1324 for cls in of_g.ordered_messages:
1325 out.write(" \"%s\",\n" % cls)
1326 out.write("\n /* Non-message objects */\n")
1327 for cls in of_g.ordered_non_messages:
1328 out.write(" \"%s\",\n" % cls)
1329 out.write("\n /* List objects */\n")
1330 for cls in of_g.ordered_list_objects:
1331 out.write(" \"%s\",\n" % cls)
1332 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1333 for cls in of_g.ordered_pseudo_objects:
1334 out.write(" \"%s\",\n" % cls)
1335 out.write("\n \"of_unknown_object\"\n};\n")
1336
1337 # We'll do version strings while we're at it
1338 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001339 const char *const of_version_str[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001340 "Unknown OpenFlow Version",
1341 "OpenFlow-1.0",
1342 "OpenFlow-1.1",
1343 "OpenFlow-1.2"
1344};
1345
1346const of_mac_addr_t of_mac_addr_all_ones = {
1347 {
1348 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1349 }
1350};
1351/* Just to be explicit; static duration vars are init'd to 0 */
1352const of_mac_addr_t of_mac_addr_all_zeros = {
1353 {
1354 0, 0, 0, 0, 0, 0
1355 }
1356};
1357
1358const of_ipv6_t of_ipv6_all_ones = {
1359 {
1360 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1361 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1362 }
1363};
1364/* Just to be explicit; static duration vars are init'd to 0 */
1365const of_ipv6_t of_ipv6_all_zeros = {
1366 {
1367 0, 0, 0, 0, 0, 0, 0, 0,
1368 0, 0, 0, 0, 0, 0, 0, 0
1369 }
1370};
1371
1372/** @var of_error_strings
1373 * The error string map; use abs value to index
1374 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001375const char *const of_error_strings[] = { OF_ERROR_STRINGS };
Rich Lanea06d0c32013-03-25 08:52:03 -07001376""")
1377
1378################################################################
1379#
1380# Internal Utility Functions
1381#
1382################################################################
1383
1384
1385def acc_name(cls, m_name):
1386 """
1387 Generate the root name of an accessor function for typedef
1388 @param cls The class name
1389 @param m_name The member name
1390 """
1391 (m_type, get_rv) = get_acc_rv(cls, m_name)
1392 return "%s_%s" % (cls, m_type)
1393
1394def get_acc_rv(cls, m_name):
1395 """
1396 Determine the data type and return type for a get accessor.
1397
1398 The return type may be "void" or it may be the accessor type
1399 depending on the system configuration and on the data type.
1400
1401 @param cls The class name
1402 @param m_name The member name
1403 @return A pair (m_type, rv) where m_type is the unified type of the
1404 member and rv is the get_accessor return type
1405 """
1406 member = of_g.unified[cls]["union"][m_name]
1407 m_type = member["m_type"]
1408 rv = "int"
1409 if member_returns_val(cls, m_name):
1410 rv = m_type
1411 if m_type[-2:] == "_t":
1412 m_type = m_type[:-2]
1413
1414 return (m_type, rv)
1415
1416def param_list(cls, m_name, a_type):
1417 """
1418 Generate the parameter list (no parens) for an a_type accessor
1419 @param cls The class name
1420 @param m_name The member name
1421 @param a_type One of "set" or "get" or TBD
1422 """
1423 member = of_g.unified[cls]["union"][m_name]
1424 m_type = member["m_type"]
1425 params = ["%s_t *obj" % cls]
1426 if a_type == "set":
1427 if loxi_utils.type_is_scalar(m_type):
1428 params.append("%s %s" % (m_type, m_name))
1429 else:
1430 params.append("%s *%s" % (m_type, m_name))
1431 elif a_type in ["get", "bind"]:
1432 params.append("%s *%s" % (m_type, m_name))
1433 else:
1434 debug("Class %s, name %s Bad param list a_type: %s" %
1435 (cls, m_name, a_type))
1436 sys.exit(1)
1437 return params
1438
1439def typed_function_base(cls, m_name):
1440 """
1441 Generate the core name for accessors based on the type
1442 @param cls The class name
1443 @param m_name The member name
1444 """
1445 (m_type, get_rv) = get_acc_rv(cls, m_name)
1446 return "%s_%s" % (cls, m_type)
1447
1448def member_function_base(cls, m_name):
1449 """
1450 Generate the core name for accessors based on the member name
1451 @param cls The class name
1452 @param m_name The member name
1453 """
1454 return "%s_%s" % (cls, m_name)
1455
1456def field_ver_get(cls, m_name):
1457 """
1458 Generate a dict, indexed by wire version, giving a pair (type, offset)
1459
1460 @param cls The class name
1461 @param m_name The name of the class member
1462
1463 If offset is not known for m_name, the type
1464 A dict is used for more convenient indexing.
1465 """
1466 result = {}
1467
1468 for ver in of_g.unified[cls]:
1469 if type(ver) == type(0): # It's a version
1470 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1471 ref_ver = of_g.unified[cls][ver]["use_version"]
1472 members = of_g.unified[cls][ref_ver]["members"]
1473 else:
1474 members = of_g.unified[cls][ver]["members"]
1475 idx = loxi_utils.member_to_index(m_name, members)
1476 if (idx < 0):
1477 continue # Member not in this version
1478 m_type = members[idx]["m_type"]
1479 offset = members[idx]["offset"]
1480
1481 # If m_type is mixed, get wire version type from global data
1482 if m_type in of_g.of_mixed_types and \
1483 ver in of_g.of_mixed_types[m_type]:
1484 m_type = of_g.of_mixed_types[m_type][ver]
1485
1486 # add version to result list
1487 result[ver] = (m_type, offset)
1488
1489 return result
1490
1491def v3_match_offset_get(cls):
1492 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001493 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001494 otherwise return -1
1495 """
1496 result = field_ver_get(cls, "match")
1497 if of_g.VERSION_1_2 in result:
1498 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1499 return result[of_g.VERSION_1_2][1]
1500 return -1
1501
1502################################################################
1503#
1504# OpenFlow Object Definitions
1505#
1506################################################################
1507
1508
1509def gen_of_object_defs(out):
1510 """
1511 Generate low level of_object core operations
1512 @param out The file for output, already open
1513 """
1514
1515def gen_generics(out):
1516 for (cls, subclasses) in type_maps.inheritance_map.items():
1517 out.write("""
1518/**
1519 * Inheritance super class for %(cls)s
1520 *
1521 * This class is the union of %(cls)s classes. You can refer
1522 * to it untyped by refering to the member 'header' whose structure
1523 * is common across all sub-classes.
1524 */
1525
1526union %(cls)s_u {
1527 %(cls)s_header_t header; /* Generic instance */
1528""" % dict(cls=cls))
1529 for subcls in sorted(subclasses):
1530 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1531 out.write("};\n")
1532
1533def gen_struct_typedefs(out):
1534 """
1535 Generate typedefs for all struct objects
1536 @param out The file for output, already open
1537 """
1538
1539 out.write("\n/* LOCI inheritance parent typedefs */\n")
1540 for cls in type_maps.inheritance_map:
1541 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1542 out.write("\n/* LOCI object typedefs */\n")
1543 for cls in of_g.standard_class_order:
1544 if cls in type_maps.inheritance_map:
1545 continue
1546 if config_check("gen_fn_ptrs"):
1547 out.write("typedef struct %(cls)s_s %(cls)s_t;\n" % dict(cls=cls))
1548 else:
1549 template = "typedef of_object_t %(cls)s_t;\n"
1550 out.write(template % dict(cls=cls))
1551
1552 out.write("""
1553/****************************************************************
1554 *
1555 * Additional of_object defines
1556 * These are needed for some static inline ops, so we put them here.
1557 *
1558 ****************************************************************/
1559
1560/* Delete an OpenFlow object without reference to its type */
1561extern void of_object_delete(of_object_t *obj);
1562
1563""")
1564
1565def gen_generic_union(out):
1566 """
1567 Generate the generic union object composing all LOCI objects
1568
1569 @param out The file to which to write the decs
1570 """
1571 out.write("""
1572/**
1573 * The common LOCI object is a union of all possible objects.
1574 */
1575union of_generic_u {
1576 of_object_t object; /* Common base class with fundamental accessors */
1577
1578 /* Message objects */
1579""")
1580 for cls in of_g.ordered_messages:
1581 out.write(" %s_t %s;\n" % (cls, cls))
1582 out.write("\n /* Non-message composite objects */\n")
1583 for cls in of_g.ordered_non_messages:
1584 if cls in type_maps.inheritance_map:
1585 continue
1586 out.write(" %s_t %s;\n" % (cls, cls))
1587 out.write("\n /* List objects */\n")
1588 for cls in of_g.ordered_list_objects:
1589 out.write(" %s_t %s;\n" % (cls, cls))
1590 out.write("};\n")
1591
1592def gen_common_struct_definitions(out):
1593 out.write("""
1594/****************************************************************
1595 *
1596 * Unified structure definitions
1597 *
1598 ****************************************************************/
1599
1600struct of_object_s {
1601 /* Common members */
1602%(common)s
1603};
1604""" % dict(common=of_g.base_object_members))
1605
1606def gen_flow_add_setup_function_declarations(out):
1607 """
1608 Add the declarations for functions that can be initialized
1609 by a flow add. These are defined external to LOXI.
1610 """
1611
1612 out.write("""
1613/****************************************************************
1614 * Functions for objects that can be initialized by a flow add message.
1615 * These are defined in a non-autogenerated file
1616 ****************************************************************/
1617
1618/**
1619 * @brief Set up a flow removed message from the original add
1620 * @param obj The flow removed message being updated
1621 * @param flow_add The flow_add message to use
1622 *
1623 * Initialize the following fields of obj to be identical
1624 * to what was originally on the wire from the flow_add object:
1625 * match
1626 * cookie
1627 * priority
1628 * idle_timeout
1629 * hard_timeout
1630 *
1631 */
1632
1633extern int
1634of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1635 of_flow_add_t *flow_add);
1636
1637
1638/**
1639 * @brief Set up the packet in match structure from the original add
1640 * @param obj The packet in message being updated
1641 * @param flow_add The flow_add message to use
1642 * @returns Indigo error code. Does not return a version error if
1643 * the version does not require initializing obj.
1644 *
1645 * Initialize the match member of obj to be identical to what was originally
1646 * on the wire from the flow_add object. If applicable, the table ID is also
1647 * initialized from the flow_add object.
1648 *
1649 * This API applies to 1.2 and later only.
1650 */
1651
1652extern int
1653of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1654 of_flow_add_t *flow_add);
1655
1656
1657/**
1658 * @brief Set up the flow stats entry from the original add
1659 * @param obj The packet in message being updated
1660 * @param flow_add The flow_add message to use
1661 * @param effects Optional actions or instructions; see below.
1662 *
1663 * Initialize the following fields of obj to be identical
1664 * to what was originally on the wire from the flow_add object:
1665 * match
1666 * actions/instructions (effects)
1667 * cookie
1668 * priority
1669 * idle_timeout
1670 * hard_timeout
1671 *
Andreas Wundsam53256162013-05-02 14:05:53 -07001672 * Note that the actions/instructions of a flow may be modified by a
Rich Lanea06d0c32013-03-25 08:52:03 -07001673 * subsequent flow modify message. To facilitate implementations,
1674 * the "effects" parameter is provided. If effects is NULL, the
1675 * actions/instructions are taken from the flow_add message.
1676 * Otherwise, effects is coerced to the proper type (actions or
1677 * instructions) and used to init obj.
1678 */
1679
1680extern int
1681of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1682 of_flow_add_t *flow_add,
1683 of_object_t *effects);
1684""")
1685
1686def gen_struct_definitions(out):
1687 """
1688 Generate the declaration of all of_ C structures
1689
1690 @param out The file to which to write the decs
1691 """
1692
1693 # This should only get called if gen_fn_ptr is true in code_gen_config
1694 if not config_check("gen_fn_ptrs"):
1695 debug("Error: gen_struct_defs called, but no fn ptrs set")
1696 return
1697
1698 for cls in of_g.standard_class_order:
1699 if cls in type_maps.inheritance_map:
1700 continue # These are generated elsewhere
1701 note = ""
1702 if loxi_utils.class_is_message(cls):
1703 note = " /* Class is message */"
1704 out.write("struct %s_s {%s\n" % (cls, note))
1705 out.write(""" /* Common members */
1706%s
1707 /* Class specific members */
1708""" % of_g.base_object_members)
1709 if loxi_utils.class_is_list(cls):
1710 out.write("""
1711 %(cls)s_first_f first;
1712 %(cls)s_next_f next;
1713 %(cls)s_append_bind_f append_bind;
1714 %(cls)s_append_f append;
1715};
1716
1717""" % {"cls": cls})
1718 continue # All done with list object
1719
1720 # Else, not a list instance; add accessors for all data members
1721 for m_name in of_g.ordered_members[cls]:
1722 if m_name in of_g.skip_members:
1723 # These members (length, etc) are handled internally
1724 continue
1725 f_name = acc_name(cls, m_name)
1726 out.write(" %s_get_f %s;\n" % (f_name, m_name + "_get"))
1727 out.write(" %s_set_f %s;\n" % (f_name, m_name + "_set"))
1728 out.write("};\n\n")
1729
1730
1731################################################################
1732#
1733# List accessor code generation
1734#
1735# Currently these all implement copy on read semantics
1736#
1737################################################################
1738
1739def init_call(e_type, obj, ver, length, cw):
1740 """
1741 Generate the init call given the strings for params
1742 """
1743 hdr = "" # If inheritance type, coerce to hdr object
1744 obj_name = obj
1745 if e_type in type_maps.inheritance_map:
1746 hdr = "_header"
1747 obj_name = "(%s_header_t *)" % e_type + obj
1748
1749 return """\
1750%(e_type)s%(hdr)s_init(%(obj_name)s,
1751 %(ver)s, %(length)s, %(cw)s)\
1752""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1753 length=length, cw=cw)
1754
1755def gen_list_first(out, cls, e_type):
1756 """
1757 Generate the body of a list_first operation
1758 @param cls The class name for which code is being generated
1759 @param e_type The element type of the list
1760 @param out The file to which to write
1761 """
1762 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1763 if e_type in type_maps.inheritance_map:
1764 len_str = "obj->header.length"
1765 else:
1766 len_str = "obj->length"
1767
1768 out.write("""
1769/**
1770 * Associate an iterator with a list
1771 * @param list The list to iterate over
1772 * @param obj The list entry iteration pointer
1773 * @return OF_ERROR_RANGE if the list is empty (end of list)
1774 *
1775 * The obj instance is completely initialized. The caller is responsible
1776 * for cleaning up any wire buffers associated with obj before this call
1777 */
1778
1779int
1780%(cls)s_first(%(cls)s_t *list,
1781 %(e_type)s_t *obj)
1782{
1783 int rv;
1784
1785 %(i_call)s;
1786 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1787 return rv;
1788 }
1789""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1790
1791 # Special case flow_stats_entry lists
1792
1793 out.write("""
1794 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1795 list->length);
1796 if (%(len_str)s == 0) {
1797 return OF_ERROR_PARSE;
1798 }
1799
1800 return rv;
1801}
1802""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1803
1804
1805def gen_bind(out, cls, m_name, m_type):
1806 """
1807 Generate the body of a bind function
1808 @param out The file to which to write
1809 @param cls The class name for which code is being generated
1810 @param m_name The name of the data member
1811 @param m_type The type of the data member
1812 """
1813
1814 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1815
1816 i_call = init_call(e_type, "child", "parent->version", "0", "1")
1817
1818 out.write("""
1819/**
1820 * Bind the child object to the parent object for read processing
1821 * @param parent The parent object
1822 * @param child The child object
1823 *
1824 * The child obj instance is completely initialized.
1825 */
1826
1827int
1828%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
1829 %(e_type)s_t *child)
1830{
1831 int rv;
1832
1833 %(i_call)s;
1834
1835 /* Derive offset and length of child in parent */
Andreas Wundsam53256162013-05-02 14:05:53 -07001836 OF_TRY(of_object_child_attach(parent, child,
Rich Lanea06d0c32013-03-25 08:52:03 -07001837 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1838 return rv;
1839 }
1840""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1841
1842 # Special case flow_stats_entry lists
1843
1844 out.write("""
1845 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1846 list->length);
1847 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1848 return OF_ERROR_PARSE;
1849 }
1850
1851 return rv;
1852}
1853""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1854
1855
1856def gen_list_next(out, cls, e_type):
1857 """
1858 Generate the body of a list_next operation
1859 @param cls The class name for which code is being generated
1860 @param e_type The element type of the list
1861 @param out The file to which to write
1862 """
1863
1864 if e_type in type_maps.inheritance_map:
1865 len_str = "obj->header.length"
1866 else:
1867 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001868
Rich Lanea06d0c32013-03-25 08:52:03 -07001869 out.write("""
1870/**
1871 * Advance an iterator to the next element in a list
1872 * @param list The list being iterated
1873 * @param obj The list entry iteration pointer
1874 * @return OF_ERROR_RANGE if already at the last entry on the list
1875 *
1876 */
1877
1878int
1879%(cls)s_next(%(cls)s_t *list,
1880 %(e_type)s_t *obj)
1881{
1882 int rv;
1883
1884 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1885 return rv;
1886 }
1887
1888 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1889 list->length);
1890
1891 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1892 return OF_ERROR_PARSE;
1893 }
1894
1895 return rv;
1896}
1897""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1898
1899def gen_list_append(out, cls, e_type):
1900 """
1901 Generate the body of a list append functions
1902 @param cls The class name for which code is being generated
1903 @param e_type The element type of the list
1904 @param out The file to which to write
1905 """
1906
1907 out.write("""
1908/**
1909 * Set up to append an object of type %(e_type)s to an %(cls)s.
1910 * @param list The list that is prepared for append
1911 * @param obj Pointer to object to hold data to append
1912 *
1913 * The obj instance is completely initialized. The caller is responsible
1914 * for cleaning up any wire buffers associated with obj before this call.
1915 *
1916 * See the generic documentation for of_list_append_bind.
1917 */
1918
1919int
1920%(cls)s_append_bind(%(cls)s_t *list,
1921 %(e_type)s_t *obj)
1922{
1923 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1924}
1925
1926/**
1927 * Append an item to a %(cls)s list.
1928 *
1929 * This copies data from item and leaves item untouched.
1930 *
1931 * See the generic documentation for of_list_append.
1932 */
1933
1934int
1935%(cls)s_append(%(cls)s_t *list,
1936 %(e_type)s_t *item)
1937{
1938 return of_list_append((of_object_t *)list, (of_object_t *)item);
1939}
1940
1941""" % dict(cls=cls, e_type=e_type))
1942
1943def gen_list_accessors(out, cls):
1944 e_type = loxi_utils.list_to_entry_type(cls)
1945 gen_list_first(out, cls, e_type)
1946 gen_list_next(out, cls, e_type)
1947 gen_list_append(out, cls, e_type)
1948
1949################################################################
1950#
1951# Accessor Functions
1952#
1953################################################################
1954
Andreas Wundsam53256162013-05-02 14:05:53 -07001955
Rich Lanea06d0c32013-03-25 08:52:03 -07001956def gen_accessor_declarations(out):
1957 """
1958 Generate the declaration of each version independent accessor
1959
1960 @param out The file to which to write the decs
1961 """
1962
1963 out.write("""
1964/****************************************************************
1965 *
1966 * Unified, per-member accessor function declarations
1967 *
1968 ****************************************************************/
1969""")
1970 for cls in of_g.standard_class_order:
1971 if cls in type_maps.inheritance_map:
1972 continue
1973 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1974 for m_name in of_g.ordered_members[cls]:
1975 if m_name in of_g.skip_members:
1976 continue
1977 m_type = loxi_utils.member_base_type(cls, m_name)
1978 base_name = "%s_%s" % (cls, m_name)
1979 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1980 get_ret_type = accessor_return_type("get", m_type)
1981 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1982 set_ret_type = accessor_return_type("set", m_type)
1983 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1984 bind_ret_type = accessor_return_type("bind", m_type)
1985
1986 if loxi_utils.type_is_of_object(m_type):
1987 # Generate bind accessors, but not get accessor
1988 out.write("""
1989extern %(set_ret_type)s %(base_name)s_set(
1990 %(sparams)s);
1991extern %(bind_ret_type)s %(base_name)s_bind(
1992 %(bparams)s);
1993extern %(m_type)s *%(cls)s_%(m_name)s_get(
1994 %(cls)s_t *obj);
1995""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1996 m_name=m_name, m_type=m_type, cls=cls,
1997 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1998 else:
1999 out.write("""
2000extern %(set_ret_type)s %(base_name)s_set(
2001 %(sparams)s);
2002extern %(get_ret_type)s %(base_name)s_get(
2003 %(gparams)s);
2004""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
2005 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07002006
Rich Lanea06d0c32013-03-25 08:52:03 -07002007 if loxi_utils.class_is_list(cls):
2008 e_type = loxi_utils.list_to_entry_type(cls)
2009 out.write("""
2010extern int %(cls)s_first(
2011 %(cls)s_t *list, %(e_type)s_t *obj);
2012extern int %(cls)s_next(
2013 %(cls)s_t *list, %(e_type)s_t *obj);
2014extern int %(cls)s_append_bind(
2015 %(cls)s_t *list, %(e_type)s_t *obj);
2016extern int %(cls)s_append(
2017 %(cls)s_t *list, %(e_type)s_t *obj);
2018
2019/**
2020 * Iteration macro for list of type %(cls)s
2021 * @param list Pointer to the list being iterated over of
2022 * type %(cls)s
2023 * @param elt Pointer to an element of type %(e_type)s
2024 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
2025 */
2026#define %(u_cls)s_ITER(list, elt, rv) \\
2027 for ((rv) = %(cls)s_first((list), (elt)); \\
2028 (rv) == OF_ERROR_NONE; \\
2029 (rv) = %(cls)s_next((list), (elt)))
2030""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
2031
2032
2033def wire_accessor(m_type, a_type):
2034 """
2035 Returns the name of the a_type accessor for low level wire buff offset
2036 @param m_type The member type
2037 @param a_type The accessor type (set or get)
2038 """
2039 # Strip off _t if present
2040 if m_type in of_g.of_base_types:
2041 m_type = of_g.of_base_types[m_type]["short_name"]
2042 if m_type in of_g.of_mixed_types:
2043 m_type = of_g.of_mixed_types[m_type]["short_name"]
2044 if m_type[-2:] == "_t":
2045 m_type = m_type[:-2]
2046 if m_type == "octets":
2047 m_type = "octets_data"
2048 return "of_wire_buffer_%s_%s" % (m_type, a_type)
2049
2050def get_len_macro(cls, m_type, version):
2051 """
2052 Get the length macro for m_type in cls
2053 """
2054 if m_type.find("of_match") == 0:
2055 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
2056 if m_type.find("of_list_oxm") == 0:
2057 return "wire_match_len(obj, 0) - 4"
2058 if loxi_utils.class_is_tlv16(m_type):
2059 return "_TLV16_LEN(obj, offset)"
2060 if cls == "of_packet_out" and m_type == "of_list_action_t":
2061 return "_PACKET_OUT_ACTION_LEN(obj)"
2062 # Default is everything to the end of the object
2063 return "_END_LEN(obj, offset)"
2064
2065def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
2066 """
2067 Generate the sub-object offset and length calculations for accessors
2068 @param out File being written
2069 @param m_name Name of member
2070 @param version Wire version being processed
2071 @param a_type The accessor type (set or get)
2072 @param m_type The original member type
2073 @param offset The offset of the object or -1 if not fixed
2074 """
2075 # determine offset
2076 o_str = "%d" % offset # Default is fixed length
2077 if offset == -1:
2078 # There are currently 4 special cases for this
2079 # In general, get offset and length of predecessor
2080 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
2081 pass
2082 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
2083 pass
2084 elif (cls == "of_packet_in" and m_name == "data"):
2085 pass
2086 elif (cls == "of_packet_out" and m_name == "data"):
2087 pass
2088 else:
2089 debug("Error: Unknown member with offset == -1")
2090 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
2091 sys.exit(1)
2092 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
2093
2094 out.write("""\
2095 offset = %s;
2096""" % o_str);
2097
2098 # This could be moved to main body but for version check
2099 if not loxi_utils.type_is_scalar(m_type):
2100 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
2101 m_type == "of_match_t":
2102 len_macro = get_len_macro(cls, m_type, version)
2103 else:
2104 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
2105 out.write(" cur_len = %s;\n" % len_macro)
2106 out.write(" break;\n")
2107
2108def length_of(m_type, version):
2109 """
2110 Return the length of a type based on the version
2111 """
2112 if m_type in of_g.of_mixed_types:
2113 m_type = of_g.of_mixed_types[m_type][version]
2114 if m_type in of_g.of_base_types:
2115 return of_g.of_base_types[m_type]["bytes"]
2116 if (m_type[:-2], version) in of_g.base_length:
2117 return of_g.base_length[(m_type[:-2], version)]
2118 print "Unknown length request", m_type, version
2119 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07002120
Rich Lanea06d0c32013-03-25 08:52:03 -07002121
2122def gen_get_accessor_body(out, cls, m_type, m_name):
2123 """
2124 Generate the common operations for a get accessor
2125 """
2126 if loxi_utils.type_is_scalar(m_type):
2127 ver = "" # See if version required for scalar update
2128 if m_type in of_g.of_mixed_types:
2129 ver = "ver, "
2130 out.write("""\
2131 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
2132""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
2133
2134 if m_type == "of_port_no_t":
2135 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
2136 elif m_type == "of_octets_t":
2137 out.write("""\
2138 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
2139 %(m_name)s->bytes = cur_len;
2140 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
2141""" % dict(m_name=m_name))
2142 elif m_type == "of_match_t":
2143 out.write("""
2144 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
2145 match_octets.bytes = cur_len;
2146 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
2147 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
2148""" % dict(m_name=m_name))
2149 else:
2150 out.write("""
2151 /* Initialize child */
2152 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
2153 /* Attach to parent */
2154 %(m_name)s->parent = (of_object_t *)obj;
2155 %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
2156 %(m_name)s->wire_object.obj_offset = abs_offset;
2157 %(m_name)s->wire_object.owned = 0;
2158 %(m_name)s->length = cur_len;
2159""" % dict(m_type=m_type[:-2], m_name=m_name))
2160
2161
2162def gen_set_accessor_body(out, cls, m_type, m_name):
2163 """
2164 Generate the contents of a set accessor
2165 """
2166 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2167 ver = "" # See if version required for scalar update
2168 if m_type in of_g.of_mixed_types:
2169 ver = "ver, "
2170 cur_len = "" # See if version required for scalar update
2171 if m_type == "of_octets_t":
2172 cur_len = ", cur_len"
2173 out.write("""\
2174 new_len = %(m_name)s->bytes;
2175 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
2176""" % dict(m_name=m_name))
2177 out.write("""\
2178 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
2179""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
2180 m_name=m_name))
2181
2182 elif m_type == "of_match_t":
2183 out.write("""
2184 /* Match object */
2185 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
2186 new_len = match_octets.bytes;
2187 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
2188 match_octets.data, new_len);
2189 /* Free match serialized octets */
2190 FREE(match_octets.data);
2191""" % dict(m_name=m_name))
2192
2193 else: # Other object type
2194 out.write("\n /* LOCI object type */")
2195 # Need to special case OXM list
2196 out.write("""
2197 new_len = %(m_name)s->length;
2198 /* If underlying buffer already shared; nothing to do */
2199 if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
2200 of_wire_buffer_grow(wbuf, abs_offset + new_len);
2201 /* Verify that the offsets are correct */
2202 ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
2203 /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
2204 return %(ret_success)s;
2205 }
2206
2207 /* Otherwise, replace existing object in data buffer */
2208 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
2209 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
2210""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
2211
2212 if not loxi_utils.type_is_scalar(m_type):
2213 if cls == "of_packet_out" and m_type == "of_list_action_t":
2214 out.write("""
2215 /* Special case for setting action lengths */
2216 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
2217""" % dict(m_name=m_name))
2218 elif m_type not in ["of_match_t", "of_octets_t"]:
2219 out.write("""
2220 /* @fixme Shouldn't this precede copying value's data to buffer? */
2221 if (%(m_name)s->wire_length_set != NULL) {
2222 %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
2223 }
2224""" % dict(m_name=m_name))
2225 out.write("""
2226 /* Not scalar, update lengths if needed */
2227 delta = new_len - cur_len;
2228 if (delta != 0) {
2229 /* Update parent(s) */
2230 of_object_parent_length_update((of_object_t *)obj, delta);
2231 }
2232""")
2233
2234def obj_assert_check(cls):
2235 """
2236 The body of the assert check for an accessor
2237 We allow all versions of add/delete/modify to use the same accessors
2238 """
2239 if cls in ["of_flow_modify", "of_flow_modify_strict",
2240 "of_flow_delete", "of_flow_delete_strict",
2241 "of_flow_add"]:
2242 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
2243 else:
2244 return "obj->object_id == %s" % cls.upper()
2245
2246def gen_of_object_get(out, cls, m_name, m_type):
2247 sub_cls = m_type[:-2]
2248 out.write("""
2249/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002250 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07002251 * a %(cls)s instance.
2252 *
2253 * @param obj Pointer to the source of type %(cls)s_t
2254 * @returns A pointer to a new instance of type %(m_type)s whose contents
2255 * match that of %(m_name)s from source
2256 * @returns NULL if an error occurs
2257 */
2258%(m_type)s *
2259%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
2260 %(m_type)s _%(m_name)s;
2261 %(m_type)s *_%(m_name)s_ptr;
2262
2263 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
2264 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
2265 return _%(m_name)s_ptr;
2266}
2267""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
2268
2269def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
2270 """
2271 Generate the body of a set or get accessor function
2272
2273 @param out The file to which to write the decs
2274 @param cls The class name
2275 @param m_name The member name
2276 @param ver_type_map Maps (type, offset) pairs to a list of versions
2277 @param a_type The accessor type, set or get
2278 @param m_type The original member type
2279
2280 The type values in ver_type_map are now ignored as we've pushed down
2281 the type munging to the lower level.
2282
2283 This is unified because the version switch case processing is the
2284 same for both set and get
2285 """
2286 out.write("""{
2287 of_wire_buffer_t *wbuf;
2288 int offset = 0; /* Offset of value relative to the start obj */
2289 int abs_offset; /* Offset of value relative to start of wbuf */
2290 of_version_t ver;
2291""")
2292
2293 if not loxi_utils.type_is_scalar(m_type):
2294 out.write("""\
2295 int cur_len = 0; /* Current length of object data */
2296""")
2297 if a_type == "set":
2298 out.write("""\
2299 int new_len, delta; /* For set, need new length and delta */
2300""")
2301
2302 # For match, need octet string for set/get
2303 if m_type == "of_match_t":
2304 out.write("""\
2305 of_octets_t match_octets; /* Serialized string for match */
2306""")
2307
2308 out.write("""
2309 ASSERT(%(assert_str)s);
2310 ver = obj->version;
2311 wbuf = OF_OBJECT_TO_WBUF(obj);
2312 ASSERT(wbuf != NULL);
2313
2314 /* By version, determine offset and current length (where needed) */
2315 switch (ver) {
2316""" % dict(assert_str=obj_assert_check(cls)))
2317
2318 for first in sorted(ver_type_map):
2319 (prev_t, prev_o) = ver_type_map[first]
2320 prev_len = length_of(prev_t, first)
2321 prev = first
2322 out.write(" case %s:\n" % of_g.wire_ver_map[first])
2323 break
2324
2325 for next in sorted(ver_type_map):
2326 if next == first:
2327 continue
2328
2329 (t, o) = ver_type_map[next]
2330 cur_len = length_of(t, next)
2331 if o == prev_o and cur_len == prev_len:
2332 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2333 continue
2334 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
2335 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2336 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
2337
2338 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
2339 out.write("""\
2340 default:
2341 ASSERT(0);
2342 }
2343
2344 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
2345 ASSERT(abs_offset >= 0);
2346""")
2347 if not loxi_utils.type_is_scalar(m_type):
2348 out.write(" ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
2349
2350 # Now generate the common accessor code
2351 if a_type in ["get", "bind"]:
2352 gen_get_accessor_body(out, cls, m_type, m_name)
2353 else:
2354 gen_set_accessor_body(out, cls, m_type, m_name)
2355
2356 out.write("""
2357 OF_LENGTH_CHECK_ASSERT(obj);
2358
2359 return %s;
2360}
2361""" % accessor_return_success(a_type, m_type))
2362
2363def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
2364 """
2365 For generating the bind call for OF sub-objects
2366 """
2367
2368 params = ",\n ".join(param_list(cls, m_name, "bind"))
2369 out.write("""
2370/**
2371 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
2372 * member %(m_name)s
2373 * @param obj Pointer to an object of type %(cls)s.
2374 * @param %(m_name)s Pointer to the child object of type
2375 * %(m_type)s to be filled out.
2376 * \ingroup %(cls)s
2377 *
2378 * The parameter %(m_name)s is filled out to point to the same underlying
2379 * wire buffer as its parent.
2380 *
2381 */
2382""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2383
2384 ret_type = accessor_return_type("bind", m_type)
2385 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
2386 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
2387
2388def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
2389 """
2390 For generating the get call for non- OF sub-objects
2391 """
2392 params = ",\n ".join(param_list(cls, m_name, "get"))
2393 out.write("""
2394/**
2395 * Get %(m_name)s from an object of type %(cls)s.
2396 * @param obj Pointer to an object of type %(cls)s.
2397 * @param %(m_name)s Pointer to the child object of type
2398 * %(m_type)s to be filled out.
2399 *
2400 */
2401""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2402
2403 ret_type = accessor_return_type("get", m_type)
2404 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
2405 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
2406
2407def gen_accessor_definitions(out):
2408 """
2409 Generate the body of each version independent accessor
2410
2411 @param out The file to which to write the decs
2412 """
2413
2414 out.write("""
2415/****************************************************************
2416 *
2417 * Unified accessor function definitions
2418 *
2419 ****************************************************************/
2420""")
2421 for cls in of_g.standard_class_order:
2422 if cls in type_maps.inheritance_map:
2423 continue
2424 out.write("\n/* Unified accessor functions for %s */\n" % cls)
2425 if loxi_utils.class_is_list(cls):
2426 gen_list_accessors(out, cls)
2427 continue
2428 out.write("/** \\ingroup %s \n * @{ */\n" % cls)
2429 for m_name in of_g.ordered_members[cls]:
2430 if m_name in of_g.skip_members:
2431 continue
2432 m_type = loxi_utils.member_base_type(cls, m_name)
2433 ver_type_map = field_ver_get(cls, m_name)
2434
2435 # Generate get/bind pending on member type
2436 # FIXME: Does this do the right thing for match?
2437 if loxi_utils.type_is_of_object(m_type):
2438 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
2439 gen_of_object_get(out, cls, m_name, m_type)
2440 else:
2441 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
2442
2443 # Now generate set accessor for all objects
2444 params = ",\n ".join(param_list(cls, m_name, "set"))
2445 out.write("""
2446/**
2447 * Set %(m_name)s in an object of type %(cls)s.
2448 * @param obj Pointer to an object of type %(cls)s.
2449""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2450 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2451 out.write("""\
2452 * @param %(m_name)s The value to write into the object
2453 */
2454""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2455 else:
2456 out.write("""\
2457 * @param %(m_name)s Pointer to the child of type %(m_type)s.
2458 *
2459 * If the child's wire buffer is the same as the parent's, then
2460 * nothing is done as the changes have already been registered in the
2461 * parent. Otherwise, the data in the child's wire buffer is inserted
2462 * into the parent's and the appropriate lengths are updated.
2463 */
2464""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2465 ret_type = accessor_return_type("set", m_type)
2466 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
2467 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
2468
2469 out.write("\n/** @} */\n")
2470
2471def gen_acc_pointer_typedefs(out):
2472 """
2473 Generate the function pointer typedefs for in-struct accessors
2474 @param out The file to which to write the typedefs
2475 """
2476
2477 out.write("""
2478/****************************************************************
2479 *
2480 * Accessor function pointer typedefs
2481 *
2482 ****************************************************************/
2483
2484/*
2485 * Generic accessors:
2486 *
2487 * Many objects have a length represented in the wire buffer
2488 * wire_length_get and wire_length_set access these values directly on the
2489 * wire.
2490 *
2491 * Many objects have a length represented in the wire buffer
2492 * wire_length_get and wire_length_set access these values directly on the
2493 * wire.
2494 *
2495 * FIXME: TBD if wire_length_set and wire_type_set are required.
2496 */
2497typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
2498typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
2499typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
2500typedef void (*of_wire_type_set_f)(of_object_t *obj, of_object_id_t id);
2501""")
2502 # If not using function pointers in classes, don't gen typedefs below
2503 if not config_check("gen_fn_ptrs"):
2504 return
2505
2506 # For each class, for each type it uses, generate a typedef
2507 for cls in of_g.standard_class_order:
2508 if cls in type_maps.inheritance_map:
2509 continue
2510 out.write("\n/* Accessor function pointer typedefs for %s */\n" % cls)
2511 types_done = list()
2512 for m_name in of_g.ordered_members[cls]:
2513 (m_type, get_rv) = get_acc_rv(cls, m_name)
2514 if (m_type, get_rv) in types_done:
2515 continue
2516 types_done.append((m_type, get_rv))
2517 fn = "%s_%s" % (cls, m_type)
2518 params = ", ".join(param_list(cls, m_name, "get"))
2519 out.write("typedef int (*%s_get_f)(\n %s);\n" %
2520 (fn, params))
2521
2522 params = ", ".join(param_list(cls, m_name, "set"))
2523 out.write("typedef int (*%s_set_f)(\n %s);\n" %
2524 (fn, params))
2525 if loxi_utils.class_is_list(cls):
2526 obj_type = loxi_utils.list_to_entry_type(cls)
2527 out.write("""typedef int (*%(cls)s_first_f)(
2528 %(cls)s_t *list,
2529 %(obj_type)s_t *obj);
2530typedef int (*%(cls)s_next_f)(
2531 %(cls)s_t *list,
2532 %(obj_type)s_t *obj);
2533typedef int (*%(cls)s_append_bind_f)(
2534 %(cls)s_t *list,
2535 %(obj_type)s_t *obj);
2536typedef int (*%(cls)s_append_f)(
2537 %(cls)s_t *list,
2538 %(obj_type)s_t *obj);
2539""" % {"cls":cls, "obj_type":obj_type})
2540
2541# out.write("""
2542# typedef int (*%(cls)s_get_f)(
2543# %(cls)s_t *list,
2544# %(obj_type)s_t *obj, int index);
2545# typedef int (*%(cls)s_set_f)(
2546# %(cls)s_t *list,
2547# %(obj_type)s_t *obj, int index);
2548# typedef int (*%(cls)s_append_f)(
2549# %(cls)s_t *list,
2550# %(obj_type)s_t *obj, int index);
2551# typedef int (*%(cls)s_insert_f)(
2552# %(cls)s_t *list,
2553# %(obj_type)s_t *obj, int index);
2554# typedef int (*%(cls)s_remove_f)(
2555# %(cls)s_t *list,
2556# int index);
2557# """ % {"cls":cls, "obj_type":obj_type})
2558
2559################################################################
2560#
2561# New/Delete Function Definitions
2562#
2563################################################################
2564
2565
2566################################################################
2567# First, some utility functions for new/delete
2568################################################################
2569
2570def del_function_proto(cls):
2571 """
2572 Return the prototype for the delete operator for the given class
2573 @param cls The class name
2574 """
2575 fn = "void\n"
2576 return fn
2577
2578
2579def instantiate_fn_ptrs(cls, ilvl, out):
2580 """
2581 Generate the C code to instantiate function pointers for a class
2582 @param cls The class name
2583 @param ilvl The base indentation level
2584 @param out The file to which to write the functions
2585 """
2586 for m_name in of_g.ordered_members[cls]:
2587 if m_name in of_g.skip_members:
2588 continue
2589 out.write(" " * ilvl + "obj->%s_get = %s_%s_get;\n" %
2590 (m_name, cls, m_name))
2591 out.write(" " * ilvl + "obj->%s_set = %s_%s_set;\n" %
2592 (m_name, cls, m_name))
2593
2594################################################################
2595# Routines to generate the body of new/delete functions
2596################################################################
2597
2598def gen_init_fn_body(cls, out):
2599 """
2600 Generate function body for init function
2601 @param cls The class name for the function
2602 @param out The file to which to write
2603 """
2604 if cls in type_maps.inheritance_map:
2605 param = "obj_p"
2606 else:
2607 param = "obj"
2608
2609 out.write("""
2610/**
2611 * Initialize an object of type %(cls)s.
2612 *
2613 * @param obj Pointer to the object to initialize
2614 * @param version The wire version to use for the object
2615 * @param bytes How many bytes in the object
2616 * @param clean_wire Boolean: If true, clear the wire object control struct
2617 *
2618 * If bytes < 0, then the default fixed length is used for the object
2619 *
2620 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07002621 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07002622 *
2623 * If anything other than 0 is passed in for the buffer size, the underlying
2624 * wire buffer will have 'grow' called.
2625 */
2626
2627void
2628%(cls)s_init(%(cls)s_t *%(param)s,
2629 of_version_t version, int bytes, int clean_wire)
2630{
2631""" % dict(cls=cls, param=param))
2632
2633 # Use an extra pointer to deal with inheritance classes
2634 if cls in type_maps.inheritance_map:
2635 out.write("""\
2636 %s_header_t *obj;
2637
2638 obj = &obj_p->header; /* Need instantiable subclass */
2639""" % cls)
2640
2641 out.write("""
2642 ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
2643 if (clean_wire) {
2644 MEMSET(obj, 0, sizeof(*obj));
2645 }
2646 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07002647 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002648 }
2649 obj->version = version;
2650 obj->length = bytes;
2651 obj->object_id = %(enum)s;
2652""" % dict(cls=cls, enum=enum_name(cls)))
2653 gen_coerce_ops(out, cls)
2654
2655 out.write("""
2656 /* Grow the wire buffer */
2657 if (obj->wire_object.wbuf != NULL) {
2658 int tot_bytes;
2659
2660 tot_bytes = bytes + obj->wire_object.obj_offset;
2661 of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
2662 }
2663}
2664
2665""")
2666
2667## @fixme This should also be updated once there is a map from
2668# class instance to wire length/type accessors
2669def gen_wire_push_fn(cls, out):
2670 """
2671 Generate the calls to push values into the wire buffer
2672 """
2673 if type_maps.class_is_virtual(cls):
2674 print "Push fn gen called for virtual class " + cls
2675 return
2676
2677 out.write("""
2678/**
2679 * Helper function to push values into the wire buffer
2680 */
2681static inline int
2682%(cls)s_push_wire_values(%(cls)s_t *obj)
2683{
2684""" % dict(cls=cls))
2685
2686 if loxi_utils.class_is_message(cls):
2687 out.write("""
2688 /* Message obj; push version, length and type to wire */
2689 of_message_t msg;
2690
2691 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
2692 of_message_version_set(msg, obj->version);
2693 of_message_length_set(msg, obj->length);
2694 OF_TRY(of_wire_message_object_id_set(OF_OBJECT_TO_WBUF(obj),
2695 %(name)s));
2696 }
2697""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002698
Rich Lanea06d0c32013-03-25 08:52:03 -07002699 for version in of_g.of_version_range:
2700 if type_maps.class_is_extension(cls, version):
2701 exp_name = type_maps.extension_to_experimenter_macro_name(cls)
2702 subtype = type_maps.extension_message_to_subtype(cls, version)
2703 if subtype is None or exp_name is None:
2704 print "Error in mapping extension message"
2705 print cls, version
2706 sys.exit(1)
2707 out.write("""
2708 if (obj->version == %(version)s) {
2709 of_message_experimenter_id_set(OF_OBJECT_TO_MESSAGE(obj),
2710 %(exp_name)s);
2711 of_message_experimenter_subtype_set(OF_OBJECT_TO_MESSAGE(obj),
2712 %(subtype)s);
2713 }
2714""" % dict(exp_name=exp_name, version=of_g.wire_ver_map[version],
2715 subtype=str(subtype)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002716
Rich Lanea06d0c32013-03-25 08:52:03 -07002717 else: # Not a message
2718 if loxi_utils.class_is_tlv16(cls):
2719 out.write("""
2720 /* TLV obj; set length and type */
2721 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
2722 of_tlv16_wire_object_id_set((of_object_t *)obj,
2723 %(enum)s);
2724""" % dict(enum=enum_name(cls)))
2725 # Some tlv16 types may be extensions requiring more work
2726 if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
2727 "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
2728 "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl"]:
2729 out.write("""
2730 /* Extended TLV obj; Call specific accessor */
2731 of_extension_object_id_set(obj, %(enum)s);
2732""" % dict(cls=cls, enum=enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002733
Rich Lanea06d0c32013-03-25 08:52:03 -07002734
2735 if loxi_utils.class_is_oxm(cls):
2736 out.write("""\
2737 /* OXM obj; set length and type */
2738 of_oxm_wire_length_set((of_object_t *)obj, obj->length);
2739 of_oxm_wire_object_id_set((of_object_t *)obj, %(enum)s);
2740""" % dict(enum=enum_name(cls)))
2741 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2742 out.write("""
2743 obj->wire_length_set((of_object_t *)obj, obj->length);
2744""")
2745
2746 if cls == "of_meter_stats":
2747 out.write("""
2748 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2749""" % dict(enum=enum_name(cls)))
2750
2751 out.write("""
2752 return OF_ERROR_NONE;
2753}
2754""")
2755
2756def gen_new_fn_body(cls, out):
2757 """
2758 Generate function body for new function
2759 @param cls The class name for the function
2760 @param out The file to which to write
2761 """
2762
2763 out.write("""
2764/**
2765 * \\defgroup %(cls)s %(cls)s
2766 */
2767""" % dict(cls=cls))
2768
2769 if not type_maps.class_is_virtual(cls):
2770 gen_wire_push_fn(cls, out)
2771
2772 out.write("""
2773/**
2774 * Create a new %(cls)s object
2775 *
2776 * @param version The wire version to use for the object
2777 * @return Pointer to the newly create object or NULL on error
2778 *
2779 * Initializes the new object with it's default fixed length associating
2780 * a new underlying wire buffer.
2781 *
2782 * Use new_from_message to bind an existing message to a message object,
2783 * or a _get function for non-message objects.
2784 *
2785 * \\ingroup %(cls)s
2786 */
2787
2788%(cls)s_t *
2789%(cls)s_new_(of_version_t version)
2790{
2791 %(cls)s_t *obj;
2792 int bytes;
2793
Rich Lanef70be942013-07-18 13:33:14 -07002794 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002795
2796 /* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
2797 if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
2798 return NULL;
2799 }
2800
2801 %(cls)s_init(obj, version, bytes, 0);
2802""" % dict(cls=cls, enum=enum_name(cls)))
2803 if not type_maps.class_is_virtual(cls):
2804 out.write("""
2805 if (%(cls)s_push_wire_values(obj) < 0) {
2806 FREE(obj);
2807 return NULL;
2808 }
2809""" % dict(cls=cls))
2810
2811 match_offset = v3_match_offset_get(cls)
2812 if match_offset >= 0:
2813 # Init length field for match object
2814 out.write("""
2815 /* Initialize match TLV for 1.2 */
2816 /* FIXME: Check 1.3 below */
2817 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2818 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2819 }
2820""" % dict(match_offset=match_offset))
2821 out.write("""
2822 return obj;
2823}
2824
2825#if defined(OF_OBJECT_TRACKING)
2826
2827/*
2828 * Tracking objects. Call the new function and then record location
2829 */
2830
2831%(cls)s_t *
2832%(cls)s_new_tracking(of_version_t version,
2833 const char *file, int line)
2834{
2835 %(cls)s_t *obj;
2836
2837 obj = %(cls)s_new_(version);
2838 of_object_track((of_object_t *)obj, file, line);
2839
2840 return obj;
2841}
2842#endif
2843""" % dict(cls=cls))
2844
2845
2846def gen_from_message_fn_body(cls, out):
2847 """
2848 Generate function body for from_message function
2849 @param cls The class name for the function
2850 @param out The file to which to write
2851 """
2852 out.write("""
2853/**
2854 * Create a new %(cls)s object and bind it to an existing message
2855 *
2856 * @param msg The message to bind the new object to
2857 * @return Pointer to the newly create object or NULL on error
2858 *
2859 * \ingroup %(cls)s
2860 */
2861
2862%(cls)s_t *
2863%(cls)s_new_from_message_(of_message_t msg)
2864{
2865 %(cls)s_t *obj = NULL;
2866 of_version_t version;
2867 int length;
2868
2869 if (msg == NULL) return NULL;
2870
2871 version = of_message_version_get(msg);
2872 if (!OF_VERSION_OKAY(version)) return NULL;
2873
2874 length = of_message_length_get(msg);
2875
2876 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2877 return NULL;
2878 }
2879
2880 %(cls)s_init(obj, version, 0, 0);
2881
2882 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2883 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2884 FREE(obj);
2885 return NULL;
2886 }
2887 obj->length = length;
2888 obj->version = version;
2889
2890 return obj;
2891}
2892
2893#if defined(OF_OBJECT_TRACKING)
2894
2895/*
2896 * Tracking objects. Call the new function and then record location
2897 */
2898
2899%(cls)s_t *
2900%(cls)s_new_from_message_tracking(of_message_t msg,
2901 const char *file, int line)
2902{
2903 %(cls)s_t *obj;
2904
2905 obj = %(cls)s_new_from_message_(msg);
2906 of_object_track((of_object_t *)obj, file, line);
2907
2908 return obj;
2909}
2910#endif
2911""" % dict(cls=cls))
2912
2913
2914################################################################
2915# Now the top level generator functions
2916################################################################
2917
2918def gen_new_function_declarations(out):
2919 """
2920 Gerenate the header file declarations for new operators for all classes
2921 @param out The file to which to write the decs
2922 """
2923
2924 out.write("""
2925/****************************************************************
2926 *
2927 * New operator declarations
2928 *
2929 * _new: Create a new object for writing; includes init
2930 * _new_from_message: Create a new instance of the object and bind the
2931 * message data to the object
2932 * _init: Initialize and optionally allocate buffer space for an
2933 * automatic instance
2934 *
2935 * _new and _from_message require a delete operation to be called
2936 * on the object.
2937 *
2938 ****************************************************************/
2939""")
2940 out.write("""
2941/*
2942 * If object tracking is enabled, map "new" and "new from msg"
2943 * calls to tracking versions; otherwise, directly to internal
2944 * versions of fns which have the same name but end in _.
2945 */
2946
2947#if defined(OF_OBJECT_TRACKING)
2948""")
2949 for cls in of_g.standard_class_order:
2950 out.write("""
2951extern %(cls)s_t *
2952 %(cls)s_new_tracking(of_version_t version,
2953 const char *file, int line);
2954#define %(cls)s_new(version) \\
2955 %(cls)s_new_tracking(version, \\
2956 __FILE__, __LINE__)
2957""" % dict(cls=cls))
2958 if loxi_utils.class_is_message(cls):
2959 out.write("""extern %(cls)s_t *
2960 %(cls)s_new_from_message_tracking(of_message_t msg,
2961 const char *file, int line);
2962#define %(cls)s_new_from_message(msg) \\
2963 %(cls)s_new_from_message_tracking(msg, \\
2964 __FILE__, __LINE__)
2965""" % dict(cls=cls))
2966
2967 out.write("""
2968#else /* No object tracking */
2969""")
2970 for cls in of_g.standard_class_order:
2971 out.write("""
2972#define %(cls)s_new(version) \\
2973 %(cls)s_new_(version)
2974""" % dict(cls=cls))
2975 if loxi_utils.class_is_message(cls):
2976 out.write("""#define %(cls)s_new_from_message(msg) \\
2977 %(cls)s_new_from_message_(msg)
2978""" % dict(cls=cls))
2979
2980 out.write("""
2981#endif /* Object tracking */
2982""")
2983
2984 for cls in of_g.standard_class_order:
2985 out.write("""
2986extern %(cls)s_t *
2987 %(cls)s_new_(of_version_t version);
2988""" % dict(cls=cls))
2989 if loxi_utils.class_is_message(cls):
2990 out.write("""extern %(cls)s_t *
2991 %(cls)s_new_from_message_(of_message_t msg);
2992""" % dict(cls=cls))
2993 out.write("""extern void %(cls)s_init(
2994 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2995""" % dict(cls=cls))
2996
2997 out.write("""
2998/****************************************************************
2999 *
3000 * Delete operator static inline definitions.
3001 * These are here for type checking purposes only
3002 *
3003 ****************************************************************/
3004""")
3005 for cls in of_g.standard_class_order:
3006# if cls in type_maps.inheritance_map:
3007# continue
3008 out.write("""
3009/**
3010 * Delete an object of type %(cls)s_t
3011 * @param obj An instance of type %(cls)s_t
3012 *
3013 * \ingroup %(cls)s
3014 */
3015static inline void
3016%(cls)s_delete(%(cls)s_t *obj) {
3017 of_object_delete((of_object_t *)(obj));
3018}
3019""" % dict(cls=cls))
3020
3021 out.write("""
3022typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
3023 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07003024extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07003025""")
3026
3027 out.write("""
3028/****************************************************************
3029 *
3030 * Function pointer initialization functions
3031 * These are part of the "coerce" type casting for objects
3032 *
3033 ****************************************************************/
3034""")
3035
3036#
3037# @fixme Not clear that these should all be set for virtual fns
3038#
3039# @fixme Clean up. should have a (language specific) map from class
3040# to length and type get/set functions
3041#
3042
3043def gen_coerce_ops(out, cls):
3044 out.write("""
3045 /* Set up the object's function pointers */
3046""")
3047
3048 if loxi_utils.class_is_message(cls):
3049 out.write("""
3050 obj->wire_length_get = of_object_message_wire_length_get;
3051 obj->wire_length_set = of_object_message_wire_length_set;
3052""")
3053 else:
3054 if loxi_utils.class_is_tlv16(cls):
3055 if not (cls in type_maps.inheritance_map): # Don't set for super
3056 out.write("""
3057 obj->wire_length_set = of_tlv16_wire_length_set;
3058 obj->wire_type_set = of_tlv16_wire_object_id_set;\
3059""")
3060 out.write("""
3061 obj->wire_length_get = of_tlv16_wire_length_get;
3062""")
3063 if loxi_utils.class_is_action(cls):
3064 out.write("""
3065 obj->wire_type_get = of_action_wire_object_id_get;
3066""")
3067 if loxi_utils.class_is_action_id(cls):
3068 out.write("""
3069 obj->wire_type_get = of_action_id_wire_object_id_get;
3070""")
3071 if loxi_utils.class_is_instruction(cls):
3072 out.write("""
3073 obj->wire_type_get = of_instruction_wire_object_id_get;
3074""")
3075 if loxi_utils.class_is_queue_prop(cls):
3076 out.write("""
3077 obj->wire_type_get = of_queue_prop_wire_object_id_get;
3078""")
3079 if loxi_utils.class_is_table_feature_prop(cls):
3080 out.write("""
3081 obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
3082""")
3083 if loxi_utils.class_is_meter_band(cls):
3084 out.write("""
3085 obj->wire_type_get = of_meter_band_wire_object_id_get;
3086""")
3087 if loxi_utils.class_is_hello_elem(cls):
3088 out.write("""
3089 obj->wire_type_get = of_hello_elem_wire_object_id_get;
3090""")
3091 if loxi_utils.class_is_oxm(cls):
3092 out.write("""
3093 obj->wire_length_get = of_oxm_wire_length_get;
3094 obj->wire_length_set = of_oxm_wire_length_set;
3095 obj->wire_type_get = of_oxm_wire_object_id_get;
3096 obj->wire_type_set = of_oxm_wire_object_id_set;
3097""")
3098 if loxi_utils.class_is_u16_len(cls):
3099 out.write("""
3100 obj->wire_length_get = of_u16_len_wire_length_get;
3101 obj->wire_length_set = of_u16_len_wire_length_set;
3102""")
3103 if cls == "of_packet_queue":
3104 out.write("""
3105 obj->wire_length_get = of_packet_queue_wire_length_get;
3106 obj->wire_length_set = of_packet_queue_wire_length_set;
3107""")
3108# if cls == "of_list_meter_band_stats":
3109# out.write("""
3110# obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
3111#""")
3112 if cls == "of_meter_stats":
3113 out.write("""
3114 obj->wire_length_get = of_meter_stats_wire_length_get;
3115 obj->wire_length_set = of_meter_stats_wire_length_set;
3116""")
3117
3118 if config_check("gen_fn_ptrs"):
3119 if loxi_utils.class_is_list(cls):
3120 out.write("""
3121 obj->first = %(cls)s_first;
3122 obj->next = %(cls)s_next;
3123 obj->append = %(cls)s_append;
3124 obj->append_bind = %(cls)s_append_bind;
3125""" % dict(cls=cls))
3126 else:
3127 instantiate_fn_ptrs(cls, 4, out)
3128
3129def gen_new_function_definitions(out):
3130 """
3131 Generate the new operator for all classes
3132
3133 @param out The file to which to write the functions
3134 """
3135
3136 out.write("\n/* New operators for each message class */\n")
3137 for cls in of_g.standard_class_order:
3138 out.write("\n/* New operators for %s */\n" % cls)
3139 gen_new_fn_body(cls, out)
3140 gen_init_fn_body(cls, out)
3141 if loxi_utils.class_is_message(cls):
3142 gen_from_message_fn_body(cls, out)
3143
3144def gen_init_map(out):
3145 """
3146 Generate map from object ID to type coerce function
3147 """
3148 out.write("""
3149/**
3150 * Map from object ID to type coerce function
3151 */
Rich Laneb157b0f2013-03-27 13:55:28 -07003152const of_object_init_f of_object_init_map[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07003153 (of_object_init_f)NULL,
3154""")
3155 count = 1
3156 for i, cls in enumerate(of_g.standard_class_order):
3157 if count != of_g.unified[cls]["object_id"]:
3158 print "Error in class mapping: object IDs not sequential"
3159 print cls, count, of_g.unified[cls]["object_id"]
3160 sys.exit(1)
3161 s = "(of_object_init_f)%s_init" % cls
3162 if cls in type_maps.inheritance_map:
3163 s = "(of_object_init_f)%s_header_init" % cls
3164 if i < len(of_g.standard_class_order) - 1:
3165 s += ","
3166 out.write(" %-65s /* %d */\n" % (s, count))
3167 count += 1
3168 out.write("};\n")
3169
3170"""
3171Document generation functions
3172
3173The main reason this is here is to generate documentation per
3174accessor that indicates the versions that support the interface.
3175"""
3176
3177
3178def gen_accessor_doc(out, name):
3179 """
3180 Generate documentation for each accessor function that indicates
3181 the versions supporting the accessor.
3182 """
3183
3184 common_top_matter(out, name)
3185
3186 out.write("/* DOCUMENTATION ONLY */\n")
3187
3188 for cls in of_g.standard_class_order:
3189 if cls in type_maps.inheritance_map:
3190 pass # Check this
3191
3192 out.write("""
3193/**
Andreas Wundsam53256162013-05-02 14:05:53 -07003194 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07003195 * accessors available in all versions unless noted otherwise
3196 *
3197""" % dict(cls=cls))
3198 if loxi_utils.class_is_list(cls):
3199 out.write("""\
3200 * @param first Function of type %(cls)s_first_f.
3201 * Setup a TBD class object to the first entry in the list
3202 * @param next Function of type %(cls)s_next_f.
3203 * Advance a TBD class object to the next entry in the list
3204 * @param append_bind Function of type %(cls)s_append_bind_f
3205 * Setup a TBD class object for append to the end of the current list
3206 * @param append Function of type @ref %(cls)s_append_f.
3207 * Copy an item to the end of a list
3208""" % dict(cls=cls))
3209
3210 for m_name in of_g.ordered_members[cls]:
3211 if m_name in of_g.skip_members:
3212 continue
3213 ver_type_map = field_ver_get(cls, m_name)
3214 (m_type, get_rv) = get_acc_rv(cls, m_name)
3215 if len(ver_type_map) == 3:
3216 # ver_string = "Available in all versions"
3217 ver_string = ""
3218 else:
3219 ver_string = "("
3220 for ver in sorted(ver_type_map):
3221 ver_string += " " + of_g.short_version_names[ver]
3222 ver_string += ")."
3223
3224 f_name = acc_name(cls, m_name)
3225 out.write("""\
3226 * @param %(m_name)s_get/set %(ver_string)s
3227 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
3228 * are of type %(f_name)s_get_f and _set_f.
3229 *
3230""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
3231
3232 out.write("""\
3233 */
3234typedef struct %(cls)s_s %(cls)s_t;
3235""" % dict(cls=cls))
3236
3237 out.write("#endif /* _LOCI_DOC_H_ */\n")
3238
3239################################################################
3240#
3241# For fun, here are some unified, traditional C structure representation
3242#
3243################################################################
3244
3245def gen_cof_to_wire(out):
3246 pass
3247
3248def gen_wire_to_cof(out):
3249 pass
3250
3251def gen_cof_instance(out, cls):
3252 out.write("struct c%s_s {\n" % cls)
3253 for m in of_g.ordered_members[cls]:
3254 if m in of_g.skip_members:
3255 continue
3256 entry = of_g.unified[cls]["union"][m]
3257 cof_type = type_to_cof_type(entry["m_type"])
3258 out.write(" %-20s %s;\n" % (cof_type, m))
3259 out.write("};\n\n");
3260
3261def gen_cof_structs(out):
3262 """
3263 Generate non-version specific (common) representation of structures
3264
3265 @param out The file to which to write the functions
3266 """
3267
3268 out.write("\n/* Common, unified OpenFlow structure representations */\n")
3269 for cls in of_g.standard_class_order:
3270 if cls in type_maps.inheritance_map:
3271 continue
3272 gen_cof_instance(out, cls)
3273
3274################################################################
3275#
3276# Generate code samples for applications.
3277#
3278################################################################
3279
3280def gen_code_samples(out, name):
3281 out.write("""
3282#if 0 /* Do not compile in */
3283/**
3284 * @file %(name)s
3285 *
3286 * These are code samples for inclusion in other components
3287 */
3288
3289""" % dict(name=name))
3290
3291 gen_jump_table_template(out)
3292 # These are messages that a switch might expect.
3293 msg_list = ["of_echo_request",
3294 "of_hello",
3295 "of_packet_in",
3296 "of_packet_out",
3297 "of_port_mod",
3298 "of_port_stats_request",
3299 "of_queue_get_config_request",
3300 "of_queue_stats_request",
3301 "of_flow_add",
3302 "of_flow_modify",
3303 "of_flow_modify_strict",
3304 "of_flow_delete",
3305 "of_flow_delete_strict",
3306 "of_get_config_request",
3307 "of_flow_stats_request",
3308 "of_barrier_request",
3309 "of_echo_reply",
3310 "of_aggregate_stats_request",
3311 "of_desc_stats_request",
3312 "of_table_stats_request",
3313 "of_features_request",
3314 "of_table_mod",
3315 "of_set_config",
3316 "of_experimenter",
3317 "of_experimenter_stats_request",
3318 "of_group_desc_stats_request",
3319 "of_group_features_stats_request",
3320 "of_role_request"]
3321
3322 gen_message_handler_templates(out, msgs=msg_list)
3323
3324 out.write("""
3325#endif
3326""")
3327
3328def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07003329 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07003330 unhandled="unhandled_message"):
3331 """
3332 Generate a template for a jump table.
3333 @param out The file to which to write the functions
3334 """
3335 out.write("""
3336/*
3337 * Simple jump table definition for message handling
3338 */
3339typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
3340typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
3341
3342/* Jump table template for message objects */
3343extern msg_jump_table_t jump_table;
3344
3345/* C-code template */
3346msg_jump_table_t jump_table = {
3347 %(unhandled)s, /* OF_OBJECT; place holder for generic object */
3348""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3349 count = 0
3350 fn_name = unhandled
3351 for cls in of_g.ordered_messages:
3352 comma = ","
3353 count += 1
3354 if count == len(of_g.ordered_messages):
3355 comma = " "
3356 if not all_unhandled:
3357 fn_name = "%s_handler" % cls[3:]
3358 out.write(" %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07003359
Rich Lanea06d0c32013-03-25 08:52:03 -07003360 out.write("};\n")
3361
3362def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07003363 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07003364 unhandled="unhandled_message"):
3365 out.write("""
3366/*
3367 * Simple switch statement for message handling
3368 */
3369
3370 switch (obj->object_id):
3371""")
3372 fn_name = unhandled
3373 for cls in of_g.ordered_messages:
3374 if not all_unhandled:
3375 fn_name = "%s_handler" % cls[3:]
3376 out.write("""
3377 case %(enum)s:
3378 rv = %(fn_name)s(cxn, obj);
3379 break;
3380""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
3381 out.write("""
3382 default:
3383 rv = LS_ERROR_PARAM;
3384 break;
3385 }
3386
3387 TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
3388
3389 return rv;
3390""")
3391
3392
3393def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
3394 unhandled="unhandled_message", msgs=None):
3395 gen_jump_table_template(out, False, cxn_type)
3396 out.write("""
3397/**
3398 * Function for unhandled message
3399 */
3400static int
3401unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
3402{
3403 (void)cxn;
3404 (void)obj;
3405 TRACE("Unhandled message %%p. Object id %%d", obj, obj->object_id);
3406
3407 return LS_ERROR_UNAVAIL;
3408}
3409""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3410
3411 if not msgs:
3412 msgs = of_g.ordered_messages
3413 for cls in msgs:
3414 out.write("""
3415/**
3416 * Handle a %(s_cls)s message
3417 * @param cxn Connection handler for the owning connection
3418 * @param _obj Generic type object for the message to be coerced
3419 * @returns Error code
3420 */
3421
3422static int
3423%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
3424{
3425 %(cls)s_t *obj;
3426
3427 TRACE("Handling %(cls)s message: %%p.", obj);
3428 obj = (%(cls)s_t *)_obj;
3429
3430 /* Handle object of type %(cls)s_t */
3431
3432 return LS_ERROR_NONE;
3433}
3434""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
3435 gen_message_switch_stmt_tmeplate(out, False, cxn_type)
3436
3437def gen_setup_from_add_fns(out):
3438 """
3439 Generate functions that setup up objects based on an add
3440
3441 Okay, this is getting out of hand. We need to refactor the code
3442 so that this can be done without so much pain.
3443 """
3444 out.write("""
3445
3446/* Flow stats entry setup for all versions */
3447
3448static int
3449flow_stats_entry_setup_from_flow_add_common(of_flow_stats_entry_t *obj,
3450 of_flow_add_t *flow_add,
3451 of_object_t *effects,
3452 int entry_match_offset,
3453 int add_match_offset)
3454{
Rich Lanea06d0c32013-03-25 08:52:03 -07003455 int entry_len, add_len;
3456 of_wire_buffer_t *wbuf;
3457 int abs_offset;
3458 int delta;
3459 uint16_t val16;
3460 uint64_t cookie;
3461 of_octets_t match_octets;
3462
Rich Lanea06d0c32013-03-25 08:52:03 -07003463 /* Transfer the match underlying object from add to stats entry */
3464 wbuf = OF_OBJECT_TO_WBUF(obj);
3465 entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset);
3466 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3467
3468 match_octets.bytes = add_len;
3469 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3470
3471 /* Copy data into flow entry */
3472 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, entry_match_offset);
3473 of_wire_buffer_replace_data(wbuf, abs_offset, entry_len,
3474 match_octets.data, add_len);
3475
3476 /* Not scalar, update lengths if needed */
3477 delta = add_len - entry_len;
3478 if (delta != 0) {
3479 /* Update parent(s) */
3480 of_object_parent_length_update((of_object_t *)obj, delta);
3481 }
3482
3483 of_flow_add_cookie_get(flow_add, &cookie);
3484 of_flow_stats_entry_cookie_set(obj, cookie);
3485
3486 of_flow_add_priority_get(flow_add, &val16);
3487 of_flow_stats_entry_priority_set(obj, val16);
3488
3489 of_flow_add_idle_timeout_get(flow_add, &val16);
3490 of_flow_stats_entry_idle_timeout_set(obj, val16);
3491
3492 of_flow_add_hard_timeout_get(flow_add, &val16);
3493 of_flow_stats_entry_hard_timeout_set(obj, val16);
3494
Rich Lane9277a962013-07-12 09:37:41 -07003495 /* Effects may come from different places */
3496 if (effects != NULL) {
3497 if (obj->version == OF_VERSION_1_0) {
3498 OF_TRY(of_flow_stats_entry_actions_set(obj,
3499 (of_list_action_t *)effects));
3500 } else {
3501 OF_TRY(of_flow_stats_entry_instructions_set(obj,
3502 (of_list_instruction_t *)effects));
3503 }
3504 } else {
3505 if (obj->version == OF_VERSION_1_0) {
3506 of_list_action_t actions;
3507 of_flow_add_actions_bind(flow_add, &actions);
3508 OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
3509 } else {
3510 of_list_instruction_t instructions;
3511 of_flow_add_instructions_bind(flow_add, &instructions);
3512 OF_TRY(of_flow_stats_entry_instructions_set(obj, &instructions));
3513 }
3514 }
3515
Rich Lanea06d0c32013-03-25 08:52:03 -07003516 return OF_ERROR_NONE;
3517}
3518
3519/* Flow removed setup for all versions */
3520
3521static int
3522flow_removed_setup_from_flow_add_common(of_flow_removed_t *obj,
3523 of_flow_add_t *flow_add,
3524 int removed_match_offset,
3525 int add_match_offset)
3526{
3527 int add_len, removed_len;
3528 of_wire_buffer_t *wbuf;
3529 int abs_offset;
3530 int delta;
3531 uint16_t val16;
3532 uint64_t cookie;
3533 of_octets_t match_octets;
3534
3535 /* Transfer the match underlying object from add to removed obj */
3536 wbuf = OF_OBJECT_TO_WBUF(obj);
3537 removed_len = _WIRE_MATCH_PADDED_LEN(obj, removed_match_offset);
3538 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3539
3540 match_octets.bytes = add_len;
3541 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3542
3543 /* Copy data into flow removed */
3544 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, removed_match_offset);
3545 of_wire_buffer_replace_data(wbuf, abs_offset, removed_len,
3546 match_octets.data, add_len);
3547
3548 /* Not scalar, update lengths if needed */
3549 delta = add_len - removed_len;
3550 if (delta != 0) {
3551 /* Update parent(s) */
3552 of_object_parent_length_update((of_object_t *)obj, delta);
3553 }
3554
3555 of_flow_add_cookie_get(flow_add, &cookie);
3556 of_flow_removed_cookie_set(obj, cookie);
3557
3558 of_flow_add_priority_get(flow_add, &val16);
3559 of_flow_removed_priority_set(obj, val16);
3560
3561 of_flow_add_idle_timeout_get(flow_add, &val16);
3562 of_flow_removed_idle_timeout_set(obj, val16);
Andreas Wundsam53256162013-05-02 14:05:53 -07003563
Rich Lanea06d0c32013-03-25 08:52:03 -07003564 if (obj->version >= OF_VERSION_1_2) {
3565 of_flow_add_hard_timeout_get(flow_add, &val16);
3566 of_flow_removed_hard_timeout_set(obj, val16);
3567 }
3568
3569 return OF_ERROR_NONE;
3570}
3571
3572/* Set up a flow removed message from the original add */
3573
3574int
3575of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
3576 of_flow_add_t *flow_add)
3577{
3578 switch (obj->version) {
3579 case OF_VERSION_1_0:
Andreas Wundsam53256162013-05-02 14:05:53 -07003580 return flow_removed_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003581 8, 8);
3582 break;
3583 case OF_VERSION_1_1:
3584 case OF_VERSION_1_2:
3585 case OF_VERSION_1_3:
Andreas Wundsam53256162013-05-02 14:05:53 -07003586 return flow_removed_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003587 48, 48);
3588 break;
3589 default:
3590 return OF_ERROR_VERSION;
3591 break;
3592 }
3593
3594 return OF_ERROR_NONE;
3595}
3596
3597
3598/* Set up a packet in message from the original add */
3599
3600int
3601of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
3602 of_flow_add_t *flow_add)
3603{
3604 int add_len, pkt_in_len;
3605 of_wire_buffer_t *wbuf;
3606 int abs_offset;
3607 int delta;
3608 const int pkt_in_match_offset = 16;
3609 const int add_match_offset = 48;
3610 of_octets_t match_octets;
3611
3612 if (obj->version < OF_VERSION_1_2) {
3613 /* Nothing to be done before OF 1.2 */
3614 return OF_ERROR_NONE;
3615 }
3616
3617 /* Transfer match struct from flow add to packet in object */
3618 wbuf = OF_OBJECT_TO_WBUF(obj);
3619 pkt_in_len = _WIRE_MATCH_PADDED_LEN(obj, pkt_in_match_offset);
3620 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3621
3622 match_octets.bytes = add_len;
3623 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3624
3625 /* Copy data into pkt_in msg */
3626 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, pkt_in_match_offset);
3627 of_wire_buffer_replace_data(wbuf, abs_offset, pkt_in_len,
3628 match_octets.data, add_len);
3629
3630 /* Not scalar, update lengths if needed */
3631 delta = add_len - pkt_in_len;
3632 if (delta != 0) {
3633 /* Update parent(s) */
3634 of_object_parent_length_update((of_object_t *)obj, delta);
3635 }
3636
3637 return OF_ERROR_NONE;
3638}
3639
3640/* Set up a stats entry from the original add */
3641
3642int
3643of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
3644 of_flow_add_t *flow_add,
3645 of_object_t *effects)
3646{
3647 switch (obj->version) {
3648 case OF_VERSION_1_0:
3649 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
3650 effects, 4, 8);
3651 break;
3652 case OF_VERSION_1_1:
3653 case OF_VERSION_1_2:
3654 case OF_VERSION_1_3:
Andreas Wundsam53256162013-05-02 14:05:53 -07003655 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003656 effects, 48, 48);
3657 break;
3658 default:
3659 return OF_ERROR_VERSION;
3660 }
3661
3662 return OF_ERROR_NONE;
3663}
3664""")