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