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