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