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