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