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