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