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