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