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