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