blob: d138103d50449070319043426c9f7c6095c1c6a9 [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
Andreas Wundsam76db0062013-11-15 13:34:41 -080034import c_gen.of_g_legacy as of_g
Rich Lanea06d0c32013-03-25 08:52:03 -070035import c_match
36from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080037from c_gen import flags, type_maps, c_type_maps
38import c_gen.loxi_utils_legacy as loxi_utils
Rich Lane92feca82013-12-10 15:57:13 -080039import loxi_globals
Rich Lanea06d0c32013-03-25 08:52:03 -070040
Andreas Wundsam542a13c2013-11-15 13:28:55 -080041import c_gen.identifiers as identifiers
Rich Lanea06d0c32013-03-25 08:52:03 -070042
Andreas Wundsam76db0062013-11-15 13:34:41 -080043# 'property' is for queues. Could be trouble
Rich Lanea06d0c32013-03-25 08:52:03 -070044
45################################################################
46#
47# Misc helper functions
48#
49################################################################
50
51def h_file_to_define(name):
52 """
53 Convert a .h file name to the define used for the header
54 """
55 h_name = name[:-2].upper()
56 h_name = "_" + h_name + "_H_"
57 return h_name
58
59def enum_name(cls):
60 """
61 Return the name used for an enum identifier for the given class
62 @param cls The class name
63 """
64 return loxi_utils.enum_name(cls)
65
Rich Lanea06d0c32013-03-25 08:52:03 -070066# TODO serialize match outside accessor?
67def accessor_return_type(a_type, m_type):
68 if loxi_utils.accessor_returns_error(a_type, m_type):
69 return "int WARN_UNUSED_RESULT"
70 else:
71 return "void"
72
73def accessor_return_success(a_type, m_type):
74 if loxi_utils.accessor_returns_error(a_type, m_type):
75 return "OF_ERROR_NONE"
76 else:
77 return ""
78
79################################################################
80#
81# Per-file generators, mapped to jump table below
82#
83################################################################
84
85def base_h_gen(out, name):
86 """
87 Generate code for base header file
88 @param out The file handle to write to
89 @param name The name of the file
90 """
91 common_top_matter(out, name)
92 base_h_content(out)
93 gen_object_enum(out)
94 out.write("""
95/****************************************************************
96 *
97 * Experimenter IDs
98 *
99 ****************************************************************/
100
101""")
102 for name, val in of_g.experimenter_name_to_id.items():
103 out.write("#define OF_EXPERIMENTER_ID_%s 0x%08x\n" %
104 (name.upper(), val))
105
106 out.write("""
107/****************************************************************
108 *
109 * OpenFlow Match version specific and generic defines
110 *
111 ****************************************************************/
112""")
113 c_match.gen_v4_match_compat(out)
114 c_match.gen_match_macros(out)
115 c_match.gen_oxm_defines(out)
116 out.write("\n#endif /* Base header file */\n")
117
118def identifiers_gen(out, filename):
119 """
120 Generate the macros for LOCI identifiers
121 @param out The file handle to write to
122 @param filename The name of the file
123 """
124 common_top_matter(out, filename)
125 out.write("""
126/**
127 * For each identifier from an OpenFlow header file, a Loxi version
128 * of the identifier is generated. For example, ofp_port_flood becomes
Andreas Wundsam53256162013-05-02 14:05:53 -0700129 * OF_PORT_DEST_FLOOD. Loxi provides the following macros related to
Rich Lanea06d0c32013-03-25 08:52:03 -0700130 * OpenFlow identifiers (using OF_IDENT_ as an example below):
131 * OF_IDENT_BY_VERSION(version) Get the value for the specific version
132 * OF_IDENT_SUPPORTED(version) Boolean: Is OF_IDENT defined for version
133 * OF_IDENT The common value across all versions if defined
134 * OF_IDENT_GENERIC A unique value across all OF identifiers
135 *
136 * For identifiers marked as flags, the following are also defined
137 * OF_IDENT_SET(flags, version)
138 * OF_IDENT_CLEAR(flags, version)
139 * OF_IDENT_TEST(flags, version)
140 *
141 * Notes:
142 *
143 * OF_IDENT_BY_VERSION(version) returns an undefined value
144 * if the passed version does not define OF_IDENT. It does not generate an
145 * error, nor record anything to the log file. If the value is the same
146 * across all defined versions, the version is ignored.
147 *
148 * OF_IDENT is only defined if the value is the same across all
149 * target LOXI versions FOR WHICH IT IS DEFINED. No error checking is
150 * done. This allows code to be written without requiring the version
151 * to be known or referenced when it doesn't matter. It does mean
152 * that when porting to a new version of OpenFlow, compile errors may
153 * occur. However, this is an indication that the existing code must
154 * be updated to account for a change in the semantics with the newly
155 * supported OpenFlow version.
156 *
157 * @fixme Currently we do not handle multi-bit flags or field values; for
158 * example, OF_TABLE_CONFIG_TABLE_MISS_CONTROLLER is the meaning for
159 * a zero value in the bits indicated by OF_TABLE_CONFIG_TABLE_MISS_MASK.
160 *
161 * @fixme Need to decide (or make a code gen option) on the requirement
162 * for defining OF_IDENT: Is it that all target versions define it and
163 * the agree? Or only that the versions which define it agree?
164 */
165""")
166
167 # Build value-by-version parameters and c_code
168 if len(of_g.target_version_list) > 1: # Supporting more than one version
169 vbv_params = []
170 vbv_code = ""
171 first = True
172 for version in of_g.target_version_list:
173 vbv_params.append("value_%s" % of_g.short_version_names[version])
174 if not first:
175 vbv_code += "\\\n "
176 else:
177 first = False
178 last_value = "value_%s" % of_g.short_version_names[version]
179 vbv_code += "((version) == %s) ? (%s) : " % \
180 (of_g.of_version_wire2name[version], last_value)
181 # @todo Using last value, can optimize out last ?
182 vbv_code += "(%s)" % last_value
183
184 out.write("""
185/**
186 * @brief True for the special case of all versions supported
187 */
188#define OF_IDENT_IN_ALL_VERSIONS 1 /* Indicates identifier in all versions */
189
190/**
191 * @brief General macro to map version to value where values given as params
192 *
193 * If unknown version is passed, use the latest version's value
194 */
195#define OF_VALUE_BY_VERSION(version, %s) \\
196 (%s)
197
198/**
199 * @brief Generic set a flag
200 */
201#define OF_FLAG_SET(flags, mask) (flags) = (flags) | (mask)
202
203/**
204 * @brief Generic test if a flag is set
205 */
206#define OF_FLAG_CLEAR(flags, mask) (flags) = (flags) & ~(mask)
207
208/**
209 * @brief Generic test if a flag is set
210 */
211#define OF_FLAG_TEST(flags, mask) ((flags) & (mask) ? 1 : 0)
212
213/**
214 * @brief Set a flag where the value is an enum indication of bit shift
215 */
216#define OF_FLAG_ENUM_SET(flags, e_val) OF_FLAG_SET(flags, 1 << (e_val))
217
218/**
219 * @brief Clear a flag where the value is an enum indication of bit shift
220 */
221#define OF_FLAG_ENUM_CLEAR(flags, e_val) OF_FLAG_CLEAR(flags, 1 << (e_val))
222
223/**
224 * @brief Test a flag where the value is an enum indication of bit shift
225 */
226#define OF_FLAG_ENUM_TEST(flags, e_val) OF_FLAG_TEST(flags, 1 << (e_val))
227""" % (", ".join(vbv_params), vbv_code))
228
229 # For each group of identifiers, bunch ident defns
230 count = 1
231 keys = of_g.identifiers_by_group.keys()
232 keys.sort()
233 for group in keys:
234 idents = of_g.identifiers_by_group[group]
235 idents.sort()
236 out.write("""
237/****************************************************************
Andreas Wundsam53256162013-05-02 14:05:53 -0700238 * Identifiers from %s
Rich Lanea06d0c32013-03-25 08:52:03 -0700239 *****************************************************************/
240""" % group)
241 for ident in idents:
242 info = of_g.identifiers[ident]
243
244 keys = info["values_by_version"].keys()
245 keys.sort()
246
247 out.write("""
248/*
249 * Defines for %(ident)s
250 * Original name %(ofp_name)s
251 */
252""" % dict(ident=ident, ofp_name=info["ofp_name"]))
253
254 # Generate supported versions macro
255 if len(keys) == len(of_g.target_version_list): # Defined for all
256 out.write("""\
257#define %(ident)s_SUPPORTED(version) OF_IDENT_IN_ALL_VERSIONS
258""" % dict(ident=ident))
259 else: # Undefined for some version
260 sup_list = []
261 for version in keys:
262 sup_list.append("((version) == %s)" %
263 of_g.of_version_wire2name[version])
264 out.write("""\
265#define %(ident)s_SUPPORTED(version) \\
266 (%(sup_str)s)
267""" % dict(ident=ident, sup_str=" || \\\n ".join(sup_list)))
268
269 # Generate value macro
270 if identifiers.defined_versions_agree(of_g.identifiers,
271 of_g.target_version_list,
272 ident):
273 out.write("""\
Rich Lanef3dc3962013-05-10 16:16:48 -0700274#define %(ident)s (%(value)#x)
275#define %(ident)s_BY_VERSION(version) (%(value)#x)
Rich Lanea06d0c32013-03-25 08:52:03 -0700276""" % dict(ident=ident,value=info["common_value"]))
277 else: # Values differ between versions
278 # Generate version check and value by version
279 val_list = []
280 # Order of params matters
281 for version in of_g.target_version_list:
282 if version in info["values_by_version"]:
283 value = info["values_by_version"][version]
284 else:
285 value = identifiers.UNDEFINED_IDENT_VALUE
Rich Lanef3dc3962013-05-10 16:16:48 -0700286 val_list.append("%#x" % value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700287 out.write("""\
288#define %(ident)s_BY_VERSION(version) \\
289 OF_VALUE_BY_VERSION(version, %(val_str)s)
290""" % dict(ident=ident, val_str=", ".join(val_list)))
291 if flags.ident_is_flag(ident):
292 log("Treating %s as a flag" % ident)
293 out.write("""
294#define %(ident)s_SET(flags, version) \\
295 OF_FLAG_SET(flags, %(ident)s_BY_VERSION(version))
296#define %(ident)s_TEST(flags, version) \\
297 OF_FLAG_TEST(flags, %(ident)s_BY_VERSION(version))
298#define %(ident)s_CLEAR(flags, version) \\
299 OF_FLAG_CLEAR(flags, %(ident)s_BY_VERSION(version))
300""" % dict(ident=ident))
301
302 out.write("#define %(ident)s_GENERIC %(count)d\n"
303 % dict(ident=ident, count=count))
304 count += 1 # This count should probably be promoted higher
305
306 log("Generated %d identifiers" % (count - 1))
307 out.write("\n#endif /* Loci identifiers header file */\n")
308
Rich Lanea06d0c32013-03-25 08:52:03 -0700309def match_h_gen(out, name):
310 """
311 Generate code for
312 @param out The file handle to write to
313 @param name The name of the file
314 """
315 c_match.match_h_top_matter(out, name)
Rich Lanea06d0c32013-03-25 08:52:03 -0700316 c_match.gen_match_struct(out)
317 c_match.gen_match_comp(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700318 out.write("\n#endif /* Match header file */\n")
319
320def top_h_gen(out, name):
321 """
322 Generate code for
323 @param out The file handle to write to
324 @param name The name of the file
325 """
326 external_h_top_matter(out, name)
327 out.write("""
328
329typedef enum loci_log_level {
330 LOCI_LOG_LEVEL_TRACE,
331 LOCI_LOG_LEVEL_VERBOSE,
332 LOCI_LOG_LEVEL_INFO,
333 LOCI_LOG_LEVEL_WARN,
334 LOCI_LOG_LEVEL_ERROR,
335 LOCI_LOG_LEVEL_MSG
336} loci_log_level_t;
337
338/**
339 * @brief Output a log message.
340 * @param level The log level.
341 * @param fname The function name.
342 * @param file The file name.
343 * @param line The line number.
344 * @param format The message format string.
345 */
346typedef int (*loci_logger_f)(loci_log_level_t level,
347 const char *fname, const char *file, int line,
348 const char *format, ...);
349
350/*
351 * This variable should be set by the user of the library to redirect logs to
352 * their log infrastructure. The default drops all logs.
353 */
354extern loci_logger_f loci_logger;
355
356/**
357 * Map a generic object to the underlying wire buffer
358 *
359 * Treat as private
360 */
361#define OF_OBJECT_TO_MESSAGE(obj) \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700362 ((of_message_t)(WBUF_BUF((obj)->wbuf)))
Rich Lanea06d0c32013-03-25 08:52:03 -0700363
364/**
365 * Macro for the fixed length part of an object
366 *
367 * @param obj The object whose extended length is being calculated
368 * @returns length in bytes of non-variable part of the object
369 */
370#define OF_OBJECT_FIXED_LENGTH(obj) \\
371 (of_object_fixed_len[(obj)->version][(obj)->object_id])
372
373/**
374 * Return the length of the object beyond its fixed length
375 *
376 * @param obj The object whose extended length is being calculated
377 * @returns length in bytes of non-variable part of the object
378 *
379 * Most variable length fields are alone at the end of a structure.
380 * Their length is a simple calculation, just the total length of
381 * the parent minus the length of the non-variable part of the
382 * parent's class type.
383 */
384
385#define OF_OBJECT_VARIABLE_LENGTH(obj) \\
386 ((obj)->length - OF_OBJECT_FIXED_LENGTH(obj))
387
Rich Lanea06d0c32013-03-25 08:52:03 -0700388extern int of_wire_buffer_of_match_get(of_object_t *obj, int offset,
389 of_match_t *match);
390extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
391 of_match_t *match, int cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -0700392""")
393
394 # gen_base_types(out)
395
Rich Lanea06d0c32013-03-25 08:52:03 -0700396 out.write("""
397/****************************************************************
398 *
399 * Declarations of maps between on-the-wire type values and LOCI identifiers
400 *
401 ****************************************************************/
Rich Lanec0e20ff2013-12-15 23:40:31 -0800402
Rich Lanec0e20ff2013-12-15 23:40:31 -0800403int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
404
405extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700406""")
Rich Lanea06d0c32013-03-25 08:52:03 -0700407 c_type_maps.gen_type_data_header(out)
408 c_match.gen_declarations(out)
409 # @fixme Move debug stuff to own fn
410 out.write("""
411/**
412 * Macro to check consistency of length for top level objects
413 *
414 * If the object has no parent then its length should match the
415 * underlying wire buffer's current bytes.
416 */
417#define OF_LENGTH_CHECK_ASSERT(obj) \\
Rich Lanee57f0432014-02-19 10:31:53 -0800418 LOCI_ASSERT(((obj)->parent != NULL) || \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700419 ((obj)->wbuf == NULL) || \\
420 (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
Rich Lanea06d0c32013-03-25 08:52:03 -0700421
422#define OF_DEBUG_DUMP
423#if defined(OF_DEBUG_DUMP)
424extern void dump_match(of_match_t *match);
425#endif /* OF_DEBUG_DUMP */
426""")
427
Rich Lane1f03f672014-08-05 00:10:00 -0700428 out.write("""
429static inline const char *
430of_class_name(of_object_t *obj)
431{
432 return of_object_id_str[obj->object_id];
433}
434""")
435
Rich Lanea06d0c32013-03-25 08:52:03 -0700436 out.write("\n#endif /* Top header file */\n")
437
438def match_c_gen(out, name):
439 """
440 Generate code for
441 @param out The file handle to write to
442 @param name The name of the file
443 """
444 c_match.match_c_top_matter(out, name)
445 c_match.gen_match_conversions(out)
446 c_match.gen_serialize(out)
447 c_match.gen_deserialize(out)
448
Rich Lanea06d0c32013-03-25 08:52:03 -0700449################################################################
450# Top Matter
451################################################################
452
453def common_top_matter(out, name):
454 loxi_utils.gen_c_copy_license(out)
455 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700456
Rich Lanea06d0c32013-03-25 08:52:03 -0700457/****************************************************************
458 * File: %s
459 *
460 * DO NOT EDIT
461 *
462 * This file is automatically generated
463 *
464 ****************************************************************/
465
466""" % name)
467
468 if name[-2:] == ".h":
469 out.write("""
470#if !defined(%(h)s)
471#define %(h)s
472
473""" % dict(h=h_file_to_define(name)))
474
475def base_h_content(out):
476 """
477 Generate base header file content
478
479 @param out The output file object
480 """
481
482 # @fixme Supported version should be generated based on input to LoxiGen
483
484 out.write("""
485/*
486 * Base OpenFlow definitions. These depend only on standard C headers
487 */
488#include <string.h>
489#include <stdint.h>
490
491/* g++ requires this to pick up PRI, etc.
492 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
493 */
494#if !defined(__STDC_FORMAT_MACROS)
495#define __STDC_FORMAT_MACROS
496#endif
497#include <inttypes.h>
498
499#include <stdlib.h>
500#include <assert.h>
501#include <loci/loci_idents.h>
502
503/**
504 * Macro to enable debugging for LOCI.
505 *
506 * This enables debug output to stdout.
507 */
508#define OF_DEBUG_ENABLE
509
510#if defined(OF_DEBUG_ENABLE)
511#include <stdio.h> /* Currently for debugging */
512#define FIXME(str) do { \\
513 fprintf(stderr, "%s\\n", str); \\
514 exit(1); \\
515 } while (0)
516#define debug printf
517#else
518#define FIXME(str)
519#define debug(str, ...)
520#endif /* OF_DEBUG_ENABLE */
521
522/**
523 * The type of a function used by the LOCI dump/show functions to
524 * output text. Essentially the same signature as fprintf. May
525 * be called many times per invocation of e.g. of_object_show().
526 */
527typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
528
529/**
530 * Check if a version is supported
531 */
Rich Lane2b49df62014-10-14 11:41:28 -0700532#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_4)
Rich Lanea06d0c32013-03-25 08:52:03 -0700533
534""")
535 gen_version_enum(out)
536 out.write("\n")
537
538 # for c_name in of_g.ofp_constants:
539 # val = str(of_g.ofp_constants[c_name])
540 # out.write("#define %s %s\n" % (c_name, val))
541 # out.write("\n")
542
543 out.write("""
544typedef enum of_error_codes_e {
545 OF_ERROR_NONE = 0,
546 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
547 OF_ERROR_PARAM = -2, /* Bad parameter */
548 OF_ERROR_VERSION = -3, /* Version not supported */
549 OF_ERROR_RANGE = -4, /* End of list indication */
550 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
551 OF_ERROR_PARSE = -6, /* Error in parsing data */
552 OF_ERROR_INIT = -7, /* Uninitialized data */
553 OF_ERROR_UNKNOWN = -8 /* Unknown error */
554} of_error_codes_t;
555
556#define OF_ERROR_STRINGS "none", \\
557 "resource", \\
558 "parameter", \\
559 "version", \\
560 "range", \\
561 "incompatible", \\
562 "parse", \\
563 "init", \\
564 "unknown"
565
Rich Laneb157b0f2013-03-27 13:55:28 -0700566extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700567
Rich Lanea8b54632014-02-19 11:17:47 -0800568#ifdef __GNUC__
569#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
570#else
571#define LOCI_NORETURN_ATTR
572#endif
573
574extern void loci_assert_fail(
575 const char *cond,
576 const char *file,
577 unsigned int line) LOCI_NORETURN_ATTR;
578
Rich Lane53757732013-02-23 17:00:10 -0800579#ifndef NDEBUG
Rich Lanea8b54632014-02-19 11:17:47 -0800580#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
Rich Lane53757732013-02-23 17:00:10 -0800581#else
Rich Lanee57f0432014-02-19 10:31:53 -0800582#define LOCI_ASSERT(val)
Rich Lane53757732013-02-23 17:00:10 -0800583#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700584
585/*
586 * Some LOCI object accessors can fail, and it's easy to forget to check.
587 * On certain compilers we can trigger a warning if the error code
588 * is ignored.
589 */
590#ifndef DISABLE_WARN_UNUSED_RESULT
591#ifdef __GNUC__
592#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
593#else
594#define WARN_UNUSED_RESULT
595#endif
596#else
597#define WARN_UNUSED_RESULT
598#endif
599
600typedef union of_generic_u of_generic_t;
601typedef struct of_object_s of_object_t;
602
603/* Define ipv4 address as uint32 */
604typedef uint32_t of_ipv4_t;
605
606/* Table ID is the OF standard uint8 */
607typedef uint8_t of_table_id_t;
608
609#define OF_MAC_ADDR_BYTES 6
610typedef struct of_mac_addr_s {
611 uint8_t addr[OF_MAC_ADDR_BYTES];
612} of_mac_addr_t;
613
614#define OF_IPV6_BYTES 16
615typedef struct of_ipv6_s {
616 uint8_t addr[OF_IPV6_BYTES];
617} of_ipv6_t;
618
Rich Lane119289c2014-12-01 13:44:08 -0800619typedef struct of_bitmap_512_s {
620 uint64_t words[8];
621} of_bitmap_512_t;
622
Rich Lanea06d0c32013-03-25 08:52:03 -0700623extern const of_mac_addr_t of_mac_addr_all_ones;
624extern const of_mac_addr_t of_mac_addr_all_zeros;
625
626extern const of_ipv6_t of_ipv6_all_ones;
627extern const of_ipv6_t of_ipv6_all_zeros;
628
Rich Lane119289c2014-12-01 13:44:08 -0800629extern const of_bitmap_512_t of_bitmap_512_all_ones;
630extern const of_bitmap_512_t of_bitmap_512_all_zeroes;
631
Rich Lanea06d0c32013-03-25 08:52:03 -0700632/**
633 * Generic zero and all-ones values of size 16 bytes.
634 *
Rich Lane119289c2014-12-01 13:44:08 -0800635 * bitmap_512 is longest data type we worry about for comparisons
Rich Lanea06d0c32013-03-25 08:52:03 -0700636 */
Rich Lane119289c2014-12-01 13:44:08 -0800637#define of_all_zero_value of_bitmap_512_all_zeroes
638#define of_all_ones_value of_bitmap_512_all_ones
Rich Lanea06d0c32013-03-25 08:52:03 -0700639
640/**
641 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
642 */
643#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
644 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
645#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
646 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
647
648/* The octets object is a struct holding pointer and length */
649typedef struct of_octets_s {
650 uint8_t *data;
651 int bytes;
652} of_octets_t;
653
654/* Macro to convert an octet object to a pointer; currently trivial */
655#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
656#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
657#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
658#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
659
660/* Currently these are categorized as scalars */
661typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700662typedef char of_app_code_t[OF_APP_CODE_LEN];
Rich Lanea06d0c32013-03-25 08:52:03 -0700663typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
664typedef char of_desc_str_t[OF_DESC_STR_LEN];
665typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
Rich Lanef8a3d002014-03-19 13:33:52 -0700666typedef char of_str64_t[64];
Brian O'Connor58a73e32015-05-28 11:51:27 -0700667typedef char of_str32_t[32];
668typedef char of_str6_t[6];
Rich Lanea06d0c32013-03-25 08:52:03 -0700669
Rich Lane3b2fd832013-09-24 13:44:08 -0700670typedef struct of_bitmap_128_s {
671 uint64_t hi;
672 uint64_t lo;
673} of_bitmap_128_t;
674
Rich Lanefab0c822013-12-30 11:46:48 -0800675typedef struct of_checksum_128_s {
676 uint64_t hi;
677 uint64_t lo;
678} of_checksum_128_t;
679
Rich Lanea06d0c32013-03-25 08:52:03 -0700680/* These are types which change across versions. */
681typedef uint32_t of_port_no_t;
682typedef uint16_t of_fm_cmd_t;
683typedef uint64_t of_wc_bmap_t;
684typedef uint64_t of_match_bmap_t;
685
686#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
687#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
688#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
689#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
690#define MALLOC(bytes) malloc(bytes)
691#define FREE(ptr) free(ptr)
692
693/** Try an operation and return on failure. */
694#define OF_TRY(op) do { \\
695 int _rv; \\
696 if ((_rv = (op)) < 0) { \\
697 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
698 return _rv; \\
699 } \\
700 } while (0)
701
702/* The extent of an OF match object is determined by its length field, but
703 * aligned to 8 bytes
704 */
705
706#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
707
Rich Lanedfcafae2014-03-06 16:56:49 -0800708#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
Rich Lanea06d0c32013-03-25 08:52:03 -0700709#define U16_NTOH(val) (val)
710#define U32_NTOH(val) (val)
711#define U64_NTOH(val) (val)
712#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
713#define U16_HTON(val) (val)
714#define U32_HTON(val) (val)
715#define U64_HTON(val) (val)
716#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
717#else /* Little Endian */
Rich Lane69e247e2014-03-05 10:27:22 -0800718#define U16_NTOH(val) (((val) >> 8) | (((val) & 0xff) << 8))
Rich Lanea06d0c32013-03-25 08:52:03 -0700719#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
720 (((val) & 0x00ff0000) >> 8) | \\
721 (((val) & 0x0000ff00) << 8) | \\
722 (((val) & 0x000000ff) << 24))
723#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
724 (((val) & 0x00ff000000000000LL) >> 40) | \\
725 (((val) & 0x0000ff0000000000LL) >> 24) | \\
726 (((val) & 0x000000ff00000000LL) >> 8) | \\
727 (((val) & 0x00000000ff000000LL) << 8) | \\
728 (((val) & 0x0000000000ff0000LL) << 24) | \\
729 (((val) & 0x000000000000ff00LL) << 40) | \\
730 (((val) & 0x00000000000000ffLL) << 56))
731#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
732#define U16_HTON(val) U16_NTOH(val)
733#define U32_HTON(val) U32_NTOH(val)
734#define U64_HTON(val) U64_NTOH(val)
735#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
736#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700737""")
738
739def external_h_top_matter(out, name):
740 """
741 Generate top matter for external header file
742
743 @param name The name of the output file
744 @param out The output file object
745 """
746 common_top_matter(out, name)
747 out.write("""
748#include <loci/loci_base.h>
749#include <loci/of_message.h>
750#include <loci/of_match.h>
751#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800752#include <loci/loci_classes.h>
Rich Lanedc46fe22014-04-03 15:10:38 -0700753#include <loci/loci_class_metadata.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700754
755/****************************************************************
756 *
757 * This file is divided into the following sections.
758 *
759 * A few object specific macros
760 * Class typedefs (no struct definitions)
761 * Per-data type accessor function typedefs
762 * Per-class new/delete function typedefs
763 * Per-class static delete functions
764 * Per-class, per-member accessor declarations
765 * Per-class structure definitions
Rich Lanea06d0c32013-03-25 08:52:03 -0700766 * Pointer set function declarations
767 * Some special case macros
768 *
769 ****************************************************************/
770""")
771
Rich Lanea06d0c32013-03-25 08:52:03 -0700772################################################################
773#
774################################################################
775
776def gen_version_enum(out):
777 """
778 Generate the enumerated type for versions in LoxiGen
779 @param out The file object to which to write the decs
780
781 This just uses the wire versions for now
782 """
783 out.write("""
784/**
785 * Enumeration of OpenFlow versions
786 *
787 * The wire protocol numbers are currently used for values of the corresponding
788 * version identifiers.
789 */
790typedef enum of_version_e {
791 OF_VERSION_UNKNOWN = 0,
792""")
793
794 is_first = True
795 max = 0
796 for v in of_g.wire_ver_map:
797 if is_first:
798 is_first = False
799 else:
800 out.write(",\n")
801 if v > max:
802 max = v
803 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
804
805 out.write("""
806} of_version_t;
807
808/**
809 * @brief Use this when declaring arrays indexed by wire version
810 */
811#define OF_VERSION_ARRAY_MAX %d
812""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700813
Rich Lanea06d0c32013-03-25 08:52:03 -0700814def gen_object_enum(out):
815 """
816 Generate the enumerated type for object identification in LoxiGen
817 @param out The file object to which to write the decs
818 """
819 out.write("""
820
821/**
822 * Enumeration of OpenFlow objects
823 *
824 * We enumerate the OpenFlow objects used internally. Note that some
825 * message types are determined both by an outer type (message type like
826 * stats_request) and an inner type (port stats). These are different
827 * messages in ofC.
828 *
829 * These values are for internal use only. They will change with
830 * different versions of ofC.
831 */
832
833typedef enum of_object_id_e {
834 /* Root object type */
835 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
836 OF_OBJECT = 0, /* Generic, untyped object */
837
838 /* OpenFlow message objects */
839""")
840 last = 0
841 msg_count = 0
842 for cls in of_g.ordered_messages:
843 out.write(" %s = %d,\n" % (enum_name(cls),
844 of_g.unified[cls]["object_id"]))
845 msg_count = of_g.unified[cls]["object_id"] + 1
846
847 out.write("\n /* Non-message objects */\n")
848 for cls in of_g.ordered_non_messages:
849 out.write(" %s = %d,\n" % (enum_name(cls),
850 of_g.unified[cls]["object_id"]))
851 last = of_g.unified[cls]["object_id"]
852 out.write("\n /* List objects */\n")
853 for cls in of_g.ordered_list_objects:
854 out.write(" %s = %d,\n" % (enum_name(cls),
855 of_g.unified[cls]["object_id"]))
856 last = of_g.unified[cls]["object_id"]
857
Rich Lanea06d0c32013-03-25 08:52:03 -0700858 out.write("""
859 OF_OBJECT_COUNT = %d
860} of_object_id_t;
861
Rich Laneb157b0f2013-03-27 13:55:28 -0700862extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700863
864#define OF_MESSAGE_OBJECT_COUNT %d
865""" % ((last + 1), msg_count))
866
Rich Lanea06d0c32013-03-25 08:52:03 -0700867################################################################
868#
869# Internal Utility Functions
870#
871################################################################
872
873
874def acc_name(cls, m_name):
875 """
876 Generate the root name of an accessor function for typedef
877 @param cls The class name
878 @param m_name The member name
879 """
880 (m_type, get_rv) = get_acc_rv(cls, m_name)
881 return "%s_%s" % (cls, m_type)
882
883def get_acc_rv(cls, m_name):
884 """
885 Determine the data type and return type for a get accessor.
886
887 The return type may be "void" or it may be the accessor type
888 depending on the system configuration and on the data type.
889
890 @param cls The class name
891 @param m_name The member name
892 @return A pair (m_type, rv) where m_type is the unified type of the
893 member and rv is the get_accessor return type
894 """
895 member = of_g.unified[cls]["union"][m_name]
896 m_type = member["m_type"]
897 rv = "int"
Rich Lanea06d0c32013-03-25 08:52:03 -0700898 if m_type[-2:] == "_t":
899 m_type = m_type[:-2]
900
901 return (m_type, rv)
902
903def param_list(cls, m_name, a_type):
904 """
905 Generate the parameter list (no parens) for an a_type accessor
906 @param cls The class name
907 @param m_name The member name
908 @param a_type One of "set" or "get" or TBD
909 """
910 member = of_g.unified[cls]["union"][m_name]
911 m_type = member["m_type"]
912 params = ["%s_t *obj" % cls]
913 if a_type == "set":
914 if loxi_utils.type_is_scalar(m_type):
915 params.append("%s %s" % (m_type, m_name))
916 else:
917 params.append("%s *%s" % (m_type, m_name))
918 elif a_type in ["get", "bind"]:
919 params.append("%s *%s" % (m_type, m_name))
920 else:
921 debug("Class %s, name %s Bad param list a_type: %s" %
922 (cls, m_name, a_type))
923 sys.exit(1)
924 return params
925
Rich Lanea06d0c32013-03-25 08:52:03 -0700926def field_ver_get(cls, m_name):
927 """
928 Generate a dict, indexed by wire version, giving a pair (type, offset)
929
930 @param cls The class name
931 @param m_name The name of the class member
932
933 If offset is not known for m_name, the type
934 A dict is used for more convenient indexing.
935 """
936 result = {}
937
938 for ver in of_g.unified[cls]:
939 if type(ver) == type(0): # It's a version
940 if "use_version" in of_g.unified[cls][ver]: # deref version ref
941 ref_ver = of_g.unified[cls][ver]["use_version"]
942 members = of_g.unified[cls][ref_ver]["members"]
943 else:
944 members = of_g.unified[cls][ver]["members"]
945 idx = loxi_utils.member_to_index(m_name, members)
946 if (idx < 0):
947 continue # Member not in this version
948 m_type = members[idx]["m_type"]
949 offset = members[idx]["offset"]
950
951 # If m_type is mixed, get wire version type from global data
952 if m_type in of_g.of_mixed_types and \
953 ver in of_g.of_mixed_types[m_type]:
954 m_type = of_g.of_mixed_types[m_type][ver]
955
956 # add version to result list
957 result[ver] = (m_type, offset)
958
959 return result
960
961def v3_match_offset_get(cls):
962 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700963 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -0700964 otherwise return -1
965 """
966 result = field_ver_get(cls, "match")
967 if of_g.VERSION_1_2 in result:
968 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
969 return result[of_g.VERSION_1_2][1]
970 return -1
971
972################################################################
973#
974# OpenFlow Object Definitions
975#
976################################################################
977
Rich Lanea06d0c32013-03-25 08:52:03 -0700978def gen_struct_typedefs(out):
979 """
980 Generate typedefs for all struct objects
981 @param out The file for output, already open
982 """
983
Rich Lanea06d0c32013-03-25 08:52:03 -0700984 out.write("\n/* LOCI object typedefs */\n")
985 for cls in of_g.standard_class_order:
Rich Lane85767872013-12-15 16:24:42 -0800986 template = "typedef of_object_t %(cls)s_t;\n"
987 out.write(template % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -0700988
989 out.write("""
990/****************************************************************
991 *
992 * Additional of_object defines
993 * These are needed for some static inline ops, so we put them here.
994 *
995 ****************************************************************/
996
997/* Delete an OpenFlow object without reference to its type */
998extern void of_object_delete(of_object_t *obj);
999
1000""")
1001
Rich Lanea06d0c32013-03-25 08:52:03 -07001002################################################################
1003#
Rich Lanea06d0c32013-03-25 08:52:03 -07001004# Accessor Functions
1005#
1006################################################################
1007
Andreas Wundsam53256162013-05-02 14:05:53 -07001008
Rich Lanea06d0c32013-03-25 08:52:03 -07001009def gen_accessor_declarations(out):
1010 """
1011 Generate the declaration of each version independent accessor
1012
1013 @param out The file to which to write the decs
1014 """
1015
1016 out.write("""
1017/****************************************************************
1018 *
1019 * Unified, per-member accessor function declarations
1020 *
1021 ****************************************************************/
1022""")
1023 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -08001024 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001025 continue
1026 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1027 for m_name in of_g.ordered_members[cls]:
1028 if m_name in of_g.skip_members:
1029 continue
1030 m_type = loxi_utils.member_base_type(cls, m_name)
1031 base_name = "%s_%s" % (cls, m_name)
1032 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1033 get_ret_type = accessor_return_type("get", m_type)
1034 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1035 set_ret_type = accessor_return_type("set", m_type)
1036 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1037 bind_ret_type = accessor_return_type("bind", m_type)
1038
1039 if loxi_utils.type_is_of_object(m_type):
1040 # Generate bind accessors, but not get accessor
1041 out.write("""
1042extern %(set_ret_type)s %(base_name)s_set(
1043 %(sparams)s);
1044extern %(bind_ret_type)s %(base_name)s_bind(
1045 %(bparams)s);
1046extern %(m_type)s *%(cls)s_%(m_name)s_get(
1047 %(cls)s_t *obj);
1048""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1049 m_name=m_name, m_type=m_type, cls=cls,
1050 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1051 else:
1052 out.write("""
1053extern %(set_ret_type)s %(base_name)s_set(
1054 %(sparams)s);
1055extern %(get_ret_type)s %(base_name)s_get(
1056 %(gparams)s);
1057""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1058 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001059
Rich Lanea06d0c32013-03-25 08:52:03 -07001060 if loxi_utils.class_is_list(cls):
1061 e_type = loxi_utils.list_to_entry_type(cls)
1062 out.write("""
1063extern int %(cls)s_first(
Rich Lane30943262014-11-07 09:04:13 -08001064 %(cls)s_t *list, of_object_t *iter);
Rich Lanea06d0c32013-03-25 08:52:03 -07001065extern int %(cls)s_next(
Rich Lane30943262014-11-07 09:04:13 -08001066 %(cls)s_t *list, of_object_t *iter);
Rich Lanea06d0c32013-03-25 08:52:03 -07001067extern int %(cls)s_append_bind(
Rich Lane30943262014-11-07 09:04:13 -08001068 %(cls)s_t *list, of_object_t *iter);
Rich Lanea06d0c32013-03-25 08:52:03 -07001069extern int %(cls)s_append(
Rich Lane30943262014-11-07 09:04:13 -08001070 %(cls)s_t *list, of_object_t *iter);
Rich Lanea06d0c32013-03-25 08:52:03 -07001071
1072/**
1073 * Iteration macro for list of type %(cls)s
1074 * @param list Pointer to the list being iterated over of
1075 * type %(cls)s
1076 * @param elt Pointer to an element of type %(e_type)s
1077 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1078 */
1079#define %(u_cls)s_ITER(list, elt, rv) \\
1080 for ((rv) = %(cls)s_first((list), (elt)); \\
1081 (rv) == OF_ERROR_NONE; \\
1082 (rv) = %(cls)s_next((list), (elt)))
1083""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1084
1085
1086def wire_accessor(m_type, a_type):
1087 """
1088 Returns the name of the a_type accessor for low level wire buff offset
1089 @param m_type The member type
1090 @param a_type The accessor type (set or get)
1091 """
1092 # Strip off _t if present
1093 if m_type in of_g.of_base_types:
1094 m_type = of_g.of_base_types[m_type]["short_name"]
1095 if m_type in of_g.of_mixed_types:
1096 m_type = of_g.of_mixed_types[m_type]["short_name"]
1097 if m_type[-2:] == "_t":
1098 m_type = m_type[:-2]
1099 if m_type == "octets":
1100 m_type = "octets_data"
1101 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1102
Rich Lane713d9282013-12-30 15:21:35 -08001103def get_len_macro(cls, m_name, m_type, version):
Rich Lanea06d0c32013-03-25 08:52:03 -07001104 """
1105 Get the length macro for m_type in cls
1106 """
1107 if m_type.find("of_match") == 0:
1108 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1109 if m_type.find("of_list_oxm") == 0:
1110 return "wire_match_len(obj, 0) - 4"
1111 if loxi_utils.class_is_tlv16(m_type):
1112 return "_TLV16_LEN(obj, offset)"
1113 if cls == "of_packet_out" and m_type == "of_list_action_t":
1114 return "_PACKET_OUT_ACTION_LEN(obj)"
Rich Lane713d9282013-12-30 15:21:35 -08001115 if cls == "of_bsn_gentable_entry_add" and m_name == "key":
1116 return "of_object_u16_get(obj, 18)"
1117 if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
1118 return "of_object_u16_get(obj, 2)"
1119 if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
1120 return "of_object_u16_get(obj, 2)"
Rich Lanea06d0c32013-03-25 08:52:03 -07001121 # Default is everything to the end of the object
1122 return "_END_LEN(obj, offset)"
1123
1124def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1125 """
1126 Generate the sub-object offset and length calculations for accessors
1127 @param out File being written
1128 @param m_name Name of member
1129 @param version Wire version being processed
1130 @param a_type The accessor type (set or get)
1131 @param m_type The original member type
1132 @param offset The offset of the object or -1 if not fixed
1133 """
1134 # determine offset
1135 o_str = "%d" % offset # Default is fixed length
1136 if offset == -1:
1137 # There are currently 4 special cases for this
1138 # In general, get offset and length of predecessor
1139 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1140 pass
1141 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1142 pass
1143 elif (cls == "of_packet_in" and m_name == "data"):
1144 pass
1145 elif (cls == "of_packet_out" and m_name == "data"):
1146 pass
Rich Lane713d9282013-12-30 15:21:35 -08001147 elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
1148 pass
1149 elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
1150 pass
1151 elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
1152 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001153 else:
1154 debug("Error: Unknown member with offset == -1")
1155 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1156 sys.exit(1)
1157 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1158
1159 out.write("""\
1160 offset = %s;
1161""" % o_str);
1162
1163 # This could be moved to main body but for version check
1164 if not loxi_utils.type_is_scalar(m_type):
1165 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1166 m_type == "of_match_t":
Rich Lane713d9282013-12-30 15:21:35 -08001167 len_macro = get_len_macro(cls, m_name, m_type, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001168 else:
1169 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1170 out.write(" cur_len = %s;\n" % len_macro)
1171 out.write(" break;\n")
1172
1173def length_of(m_type, version):
1174 """
1175 Return the length of a type based on the version
1176 """
1177 if m_type in of_g.of_mixed_types:
1178 m_type = of_g.of_mixed_types[m_type][version]
1179 if m_type in of_g.of_base_types:
1180 return of_g.of_base_types[m_type]["bytes"]
1181 if (m_type[:-2], version) in of_g.base_length:
1182 return of_g.base_length[(m_type[:-2], version)]
1183 print "Unknown length request", m_type, version
1184 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001185
Rich Lanea06d0c32013-03-25 08:52:03 -07001186
1187def gen_get_accessor_body(out, cls, m_type, m_name):
1188 """
1189 Generate the common operations for a get accessor
1190 """
1191 if loxi_utils.type_is_scalar(m_type):
1192 ver = "" # See if version required for scalar update
1193 if m_type in of_g.of_mixed_types:
1194 ver = "ver, "
1195 out.write("""\
1196 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1197""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1198
1199 if m_type == "of_port_no_t":
1200 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1201 elif m_type == "of_octets_t":
1202 out.write("""\
Rich Lanee57f0432014-02-19 10:31:53 -08001203 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001204 %(m_name)s->bytes = cur_len;
1205 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1206""" % dict(m_name=m_name))
1207 elif m_type == "of_match_t":
1208 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001209 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanee0b70cc2014-06-12 15:02:22 -07001210 OF_TRY(of_match_deserialize(ver, %(m_name)s, obj, offset, cur_len));
Rich Lanea06d0c32013-03-25 08:52:03 -07001211""" % dict(m_name=m_name))
Rich Lanec247ade2014-11-07 09:33:24 -08001212 elif m_type == "of_oxm_t":
Rich Lane90020b42014-04-07 12:05:45 -07001213 out.write("""
1214 /* Initialize child */
1215 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1216 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001217 of_object_attach(obj, %(m_name)s, offset, cur_len);
Rich Lane90020b42014-04-07 12:05:45 -07001218 of_object_wire_init(%(m_name)s, OF_OXM, 0);
1219""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanec247ade2014-11-07 09:33:24 -08001220 elif m_type == "of_bsn_vport_t":
Wilson Ngd6181882014-04-14 16:28:35 -07001221 out.write("""
1222 /* Initialize child */
1223 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1224 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001225 of_object_attach(obj, %(m_name)s, offset, cur_len);
Wilson Ngd6181882014-04-14 16:28:35 -07001226 of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
1227""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001228 else:
1229 out.write("""
1230 /* Initialize child */
1231 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1232 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001233 of_object_attach(obj, %(m_name)s, offset, cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001234""" % dict(m_type=m_type[:-2], m_name=m_name))
1235
1236
1237def gen_set_accessor_body(out, cls, m_type, m_name):
1238 """
1239 Generate the contents of a set accessor
1240 """
1241 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1242 ver = "" # See if version required for scalar update
1243 if m_type in of_g.of_mixed_types:
1244 ver = "ver, "
1245 cur_len = "" # See if version required for scalar update
1246 if m_type == "of_octets_t":
1247 cur_len = ", cur_len"
1248 out.write("""\
1249 new_len = %(m_name)s->bytes;
1250 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1251""" % dict(m_name=m_name))
1252 out.write("""\
1253 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1254""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1255 m_name=m_name))
1256
1257 elif m_type == "of_match_t":
1258 out.write("""
Rich Lanee0b70cc2014-06-12 15:02:22 -07001259 {
1260 /* Match object */
1261 of_octets_t match_octets;
1262 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1263 new_len = match_octets.bytes;
1264 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1265 match_octets.data, new_len);
1266 /* Free match serialized octets */
1267 FREE(match_octets.data);
1268 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001269""" % dict(m_name=m_name))
1270
1271 else: # Other object type
1272 out.write("\n /* LOCI object type */")
1273 # Need to special case OXM list
1274 out.write("""
1275 new_len = %(m_name)s->length;
1276 /* If underlying buffer already shared; nothing to do */
Rich Lanecdd542d2014-04-03 16:13:12 -07001277 if (obj->wbuf == %(m_name)s->wbuf) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001278 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1279 /* Verify that the offsets are correct */
Rich Lanee57f0432014-02-19 10:31:53 -08001280 LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1281 /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
Rich Lanea06d0c32013-03-25 08:52:03 -07001282 return %(ret_success)s;
1283 }
1284
1285 /* Otherwise, replace existing object in data buffer */
1286 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1287 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1288""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1289
1290 if not loxi_utils.type_is_scalar(m_type):
1291 if cls == "of_packet_out" and m_type == "of_list_action_t":
1292 out.write("""
1293 /* Special case for setting action lengths */
1294 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1295""" % dict(m_name=m_name))
Rich Lane713d9282013-12-30 15:21:35 -08001296 elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
1297 out.write("""
1298 /* Special case for setting key length */
1299 of_object_u16_set(obj, 18, %(m_name)s->length);
1300""" % dict(m_name=m_name))
1301 elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
1302 out.write("""
1303 /* Special case for setting key length */
1304 of_object_u16_set(obj, 2, %(m_name)s->length);
1305""" % dict(m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001306 elif m_type not in ["of_match_t", "of_octets_t"]:
1307 out.write("""
1308 /* @fixme Shouldn't this precede copying value's data to buffer? */
Rich Lanedc46fe22014-04-03 15:10:38 -07001309 of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001310""" % dict(m_name=m_name))
1311 out.write("""
1312 /* Not scalar, update lengths if needed */
1313 delta = new_len - cur_len;
1314 if (delta != 0) {
1315 /* Update parent(s) */
1316 of_object_parent_length_update((of_object_t *)obj, delta);
1317 }
1318""")
1319
1320def obj_assert_check(cls):
1321 """
1322 The body of the assert check for an accessor
1323 We allow all versions of add/delete/modify to use the same accessors
1324 """
1325 if cls in ["of_flow_modify", "of_flow_modify_strict",
1326 "of_flow_delete", "of_flow_delete_strict",
1327 "of_flow_add"]:
1328 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1329 else:
1330 return "obj->object_id == %s" % cls.upper()
1331
1332def gen_of_object_get(out, cls, m_name, m_type):
1333 sub_cls = m_type[:-2]
1334 out.write("""
1335/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001336 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001337 * a %(cls)s instance.
1338 *
1339 * @param obj Pointer to the source of type %(cls)s_t
1340 * @returns A pointer to a new instance of type %(m_type)s whose contents
1341 * match that of %(m_name)s from source
1342 * @returns NULL if an error occurs
1343 */
1344%(m_type)s *
1345%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1346 %(m_type)s _%(m_name)s;
1347 %(m_type)s *_%(m_name)s_ptr;
1348
1349 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1350 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1351 return _%(m_name)s_ptr;
1352}
1353""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1354
1355def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1356 """
1357 Generate the body of a set or get accessor function
1358
1359 @param out The file to which to write the decs
1360 @param cls The class name
1361 @param m_name The member name
1362 @param ver_type_map Maps (type, offset) pairs to a list of versions
1363 @param a_type The accessor type, set or get
1364 @param m_type The original member type
1365
1366 The type values in ver_type_map are now ignored as we've pushed down
1367 the type munging to the lower level.
1368
1369 This is unified because the version switch case processing is the
1370 same for both set and get
1371 """
1372 out.write("""{
1373 of_wire_buffer_t *wbuf;
1374 int offset = 0; /* Offset of value relative to the start obj */
1375 int abs_offset; /* Offset of value relative to start of wbuf */
1376 of_version_t ver;
1377""")
1378
1379 if not loxi_utils.type_is_scalar(m_type):
1380 out.write("""\
1381 int cur_len = 0; /* Current length of object data */
1382""")
1383 if a_type == "set":
1384 out.write("""\
1385 int new_len, delta; /* For set, need new length and delta */
1386""")
1387
Rich Lanea06d0c32013-03-25 08:52:03 -07001388 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001389 LOCI_ASSERT(%(assert_str)s);
Rich Lanea06d0c32013-03-25 08:52:03 -07001390 ver = obj->version;
1391 wbuf = OF_OBJECT_TO_WBUF(obj);
Rich Lanee57f0432014-02-19 10:31:53 -08001392 LOCI_ASSERT(wbuf != NULL);
Rich Lanea06d0c32013-03-25 08:52:03 -07001393
1394 /* By version, determine offset and current length (where needed) */
1395 switch (ver) {
1396""" % dict(assert_str=obj_assert_check(cls)))
1397
1398 for first in sorted(ver_type_map):
1399 (prev_t, prev_o) = ver_type_map[first]
1400 prev_len = length_of(prev_t, first)
1401 prev = first
1402 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1403 break
1404
1405 for next in sorted(ver_type_map):
1406 if next == first:
1407 continue
1408
1409 (t, o) = ver_type_map[next]
1410 cur_len = length_of(t, next)
1411 if o == prev_o and cur_len == prev_len:
1412 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1413 continue
1414 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1415 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1416 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1417
1418 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1419 out.write("""\
1420 default:
Rich Lanee57f0432014-02-19 10:31:53 -08001421 LOCI_ASSERT(0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001422 }
1423
1424 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
Rich Lanee57f0432014-02-19 10:31:53 -08001425 LOCI_ASSERT(abs_offset >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001426""")
1427 if not loxi_utils.type_is_scalar(m_type):
Rich Lanee57f0432014-02-19 10:31:53 -08001428 out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001429
1430 # Now generate the common accessor code
1431 if a_type in ["get", "bind"]:
1432 gen_get_accessor_body(out, cls, m_type, m_name)
1433 else:
1434 gen_set_accessor_body(out, cls, m_type, m_name)
1435
1436 out.write("""
1437 OF_LENGTH_CHECK_ASSERT(obj);
1438
1439 return %s;
1440}
1441""" % accessor_return_success(a_type, m_type))
1442
1443def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1444 """
1445 For generating the bind call for OF sub-objects
1446 """
1447
1448 params = ",\n ".join(param_list(cls, m_name, "bind"))
1449 out.write("""
1450/**
1451 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1452 * member %(m_name)s
1453 * @param obj Pointer to an object of type %(cls)s.
1454 * @param %(m_name)s Pointer to the child object of type
1455 * %(m_type)s to be filled out.
1456 * \ingroup %(cls)s
1457 *
1458 * The parameter %(m_name)s is filled out to point to the same underlying
1459 * wire buffer as its parent.
1460 *
1461 */
1462""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1463
1464 ret_type = accessor_return_type("bind", m_type)
1465 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1466 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1467
1468def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
1469 """
1470 For generating the get call for non- OF sub-objects
1471 """
1472 params = ",\n ".join(param_list(cls, m_name, "get"))
1473 out.write("""
1474/**
1475 * Get %(m_name)s from an object of type %(cls)s.
1476 * @param obj Pointer to an object of type %(cls)s.
1477 * @param %(m_name)s Pointer to the child object of type
1478 * %(m_type)s to be filled out.
1479 *
1480 */
1481""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1482
1483 ret_type = accessor_return_type("get", m_type)
1484 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
1485 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
1486
Rich Lanece2e4642013-12-15 12:05:45 -08001487def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001488 for m_name in of_g.ordered_members[cls]:
1489 if m_name in of_g.skip_members:
1490 continue
1491 m_type = loxi_utils.member_base_type(cls, m_name)
1492 ver_type_map = field_ver_get(cls, m_name)
1493
1494 # Generate get/bind pending on member type
1495 # FIXME: Does this do the right thing for match?
1496 if loxi_utils.type_is_of_object(m_type):
1497 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
1498 gen_of_object_get(out, cls, m_name, m_type)
1499 else:
1500 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
1501
1502 # Now generate set accessor for all objects
1503 params = ",\n ".join(param_list(cls, m_name, "set"))
1504 out.write("""
1505/**
1506 * Set %(m_name)s in an object of type %(cls)s.
1507 * @param obj Pointer to an object of type %(cls)s.
1508""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1509 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1510 out.write("""\
1511 * @param %(m_name)s The value to write into the object
1512 */
1513""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1514 else:
1515 out.write("""\
1516 * @param %(m_name)s Pointer to the child of type %(m_type)s.
1517 *
1518 * If the child's wire buffer is the same as the parent's, then
1519 * nothing is done as the changes have already been registered in the
1520 * parent. Otherwise, the data in the child's wire buffer is inserted
1521 * into the parent's and the appropriate lengths are updated.
1522 */
1523""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1524 ret_type = accessor_return_type("set", m_type)
1525 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
1526 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
1527
Rich Lanea06d0c32013-03-25 08:52:03 -07001528################################################################
1529#
1530# New/Delete Function Definitions
1531#
1532################################################################
1533
Rich Lanea06d0c32013-03-25 08:52:03 -07001534################################################################
1535# Routines to generate the body of new/delete functions
1536################################################################
1537
1538def gen_init_fn_body(cls, out):
1539 """
1540 Generate function body for init function
1541 @param cls The class name for the function
1542 @param out The file to which to write
1543 """
Rich Lanea06d0c32013-03-25 08:52:03 -07001544
1545 out.write("""
1546/**
1547 * Initialize an object of type %(cls)s.
1548 *
1549 * @param obj Pointer to the object to initialize
1550 * @param version The wire version to use for the object
1551 * @param bytes How many bytes in the object
1552 * @param clean_wire Boolean: If true, clear the wire object control struct
1553 *
1554 * If bytes < 0, then the default fixed length is used for the object
1555 *
1556 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07001557 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07001558 *
1559 * If anything other than 0 is passed in for the buffer size, the underlying
1560 * wire buffer will have 'grow' called.
1561 */
1562
1563void
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001564%(cls)s_init(of_object_t *obj,
Rich Lanea06d0c32013-03-25 08:52:03 -07001565 of_version_t version, int bytes, int clean_wire)
1566{
Rich Lanee57f0432014-02-19 10:31:53 -08001567 LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001568 if (clean_wire) {
1569 MEMSET(obj, 0, sizeof(*obj));
1570 }
1571 if (bytes < 0) {
Rich Lanee3d3fb52014-10-16 12:45:17 -07001572 bytes = of_object_fixed_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001573 }
1574 obj->version = version;
1575 obj->length = bytes;
1576 obj->object_id = %(enum)s;
Rich Lanea06d0c32013-03-25 08:52:03 -07001577
Rich Lanea06d0c32013-03-25 08:52:03 -07001578 /* Grow the wire buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -07001579 if (obj->wbuf != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001580 int tot_bytes;
1581
Rich Lanecdd542d2014-04-03 16:13:12 -07001582 tot_bytes = bytes + obj->obj_offset;
1583 of_wire_buffer_grow(obj->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -07001584 }
1585}
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001586""" % dict(cls=cls, enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001587
1588def gen_new_fn_body(cls, out):
1589 """
1590 Generate function body for new function
1591 @param cls The class name for the function
1592 @param out The file to which to write
1593 """
1594
1595 out.write("""
1596/**
1597 * \\defgroup %(cls)s %(cls)s
1598 */
1599""" % dict(cls=cls))
1600
Rich Lane37911fd2014-04-01 22:11:22 -07001601 uclass = loxi_globals.unified.class_by_name(cls)
1602 is_fixed_length = uclass and uclass.is_fixed_length
1603 max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
1604
Rich Lanea06d0c32013-03-25 08:52:03 -07001605 out.write("""
1606/**
1607 * Create a new %(cls)s object
1608 *
1609 * @param version The wire version to use for the object
1610 * @return Pointer to the newly create object or NULL on error
1611 *
1612 * Initializes the new object with it's default fixed length associating
1613 * a new underlying wire buffer.
1614 *
Rich Lanea06d0c32013-03-25 08:52:03 -07001615 * \\ingroup %(cls)s
1616 */
1617
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001618of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08001619%(cls)s_new(of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001620{
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001621 of_object_t *obj;
Rich Lanea06d0c32013-03-25 08:52:03 -07001622 int bytes;
1623
Rich Lanee3d3fb52014-10-16 12:45:17 -07001624 bytes = of_object_fixed_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001625
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001626 if ((obj = of_object_new(%(max_length)s)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001627 return NULL;
1628 }
1629
1630 %(cls)s_init(obj, version, bytes, 0);
Rich Lane37911fd2014-04-01 22:11:22 -07001631""" % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
Rich Lanea06d0c32013-03-25 08:52:03 -07001632 if not type_maps.class_is_virtual(cls):
Rich Lane7e003102014-10-14 10:40:48 -07001633 from codegen import class_metadata_dict
1634 metadata = class_metadata_dict[cls]
1635
1636 if metadata.wire_type_set != 'NULL':
1637 out.write("""\
1638 %s(obj);
1639""" % metadata.wire_type_set)
1640
1641 if metadata.wire_length_set != 'NULL':
1642 out.write("""\
1643 %s(obj, obj->length);
1644""" % metadata.wire_length_set)
Rich Lanea06d0c32013-03-25 08:52:03 -07001645
1646 match_offset = v3_match_offset_get(cls)
1647 if match_offset >= 0:
1648 # Init length field for match object
1649 out.write("""
1650 /* Initialize match TLV for 1.2 */
Rich Lanea926e312014-10-14 11:45:39 -07001651 if ((version >= OF_VERSION_1_2)) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001652 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
1653 }
1654""" % dict(match_offset=match_offset))
1655 out.write("""
1656 return obj;
1657}
Rich Lanea06d0c32013-03-25 08:52:03 -07001658""" % dict(cls=cls))
1659
1660
Rich Lanea06d0c32013-03-25 08:52:03 -07001661################################################################
1662# Now the top level generator functions
1663################################################################
1664
1665def gen_new_function_declarations(out):
1666 """
1667 Gerenate the header file declarations for new operators for all classes
1668 @param out The file to which to write the decs
1669 """
1670
1671 out.write("""
1672/****************************************************************
1673 *
1674 * New operator declarations
1675 *
1676 * _new: Create a new object for writing; includes init
Rich Lanea06d0c32013-03-25 08:52:03 -07001677 * _init: Initialize and optionally allocate buffer space for an
1678 * automatic instance
1679 *
Rich Lanebb8f17c2014-06-12 13:14:09 -07001680 * _new and requires a delete operation to be called on the object.
Rich Lanea06d0c32013-03-25 08:52:03 -07001681 *
1682 ****************************************************************/
1683""")
Rich Lanea06d0c32013-03-25 08:52:03 -07001684
1685 for cls in of_g.standard_class_order:
1686 out.write("""
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001687extern of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08001688 %(cls)s_new(of_version_t version);
Rich Lanea06d0c32013-03-25 08:52:03 -07001689""" % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001690 out.write("""extern void %(cls)s_init(
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001691 of_object_t *obj, of_version_t version, int bytes, int clean_wire);
Rich Lanea06d0c32013-03-25 08:52:03 -07001692""" % dict(cls=cls))
1693
1694 out.write("""
1695/****************************************************************
1696 *
1697 * Delete operator static inline definitions.
1698 * These are here for type checking purposes only
1699 *
1700 ****************************************************************/
1701""")
1702 for cls in of_g.standard_class_order:
Rich Lanea06d0c32013-03-25 08:52:03 -07001703 out.write("""
1704/**
1705 * Delete an object of type %(cls)s_t
1706 * @param obj An instance of type %(cls)s_t
1707 *
1708 * \ingroup %(cls)s
1709 */
1710static inline void
Rich Lane7fdaa5c2014-10-27 18:14:59 -07001711%(cls)s_delete(of_object_t *obj) {
1712 of_object_delete(obj);
Rich Lanea06d0c32013-03-25 08:52:03 -07001713}
1714""" % dict(cls=cls))
1715
1716 out.write("""
1717typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
1718 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07001719extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07001720""")
1721
1722 out.write("""
1723/****************************************************************
1724 *
1725 * Function pointer initialization functions
1726 * These are part of the "coerce" type casting for objects
1727 *
1728 ****************************************************************/
1729""")
1730
Rich Laneb604e332013-12-15 13:23:51 -08001731def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001732 """
1733 Generate the new operator for all classes
1734
1735 @param out The file to which to write the functions
1736 """
1737
Rich Laneb604e332013-12-15 13:23:51 -08001738 gen_new_fn_body(cls, out)
1739 gen_init_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07001740
Rich Lanea06d0c32013-03-25 08:52:03 -07001741"""
1742Document generation functions
1743
1744The main reason this is here is to generate documentation per
1745accessor that indicates the versions that support the interface.
1746"""
1747
1748
1749def gen_accessor_doc(out, name):
1750 """
1751 Generate documentation for each accessor function that indicates
1752 the versions supporting the accessor.
1753 """
1754
1755 common_top_matter(out, name)
1756
1757 out.write("/* DOCUMENTATION ONLY */\n")
1758
1759 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -08001760 if type_maps.class_is_virtual(cls):
1761 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001762
1763 out.write("""
1764/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001765 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07001766 * accessors available in all versions unless noted otherwise
1767 *
1768""" % dict(cls=cls))
1769 if loxi_utils.class_is_list(cls):
1770 out.write("""\
1771 * @param first Function of type %(cls)s_first_f.
1772 * Setup a TBD class object to the first entry in the list
1773 * @param next Function of type %(cls)s_next_f.
1774 * Advance a TBD class object to the next entry in the list
1775 * @param append_bind Function of type %(cls)s_append_bind_f
1776 * Setup a TBD class object for append to the end of the current list
1777 * @param append Function of type @ref %(cls)s_append_f.
1778 * Copy an item to the end of a list
1779""" % dict(cls=cls))
1780
1781 for m_name in of_g.ordered_members[cls]:
1782 if m_name in of_g.skip_members:
1783 continue
1784 ver_type_map = field_ver_get(cls, m_name)
1785 (m_type, get_rv) = get_acc_rv(cls, m_name)
1786 if len(ver_type_map) == 3:
1787 # ver_string = "Available in all versions"
1788 ver_string = ""
1789 else:
1790 ver_string = "("
1791 for ver in sorted(ver_type_map):
1792 ver_string += " " + of_g.short_version_names[ver]
1793 ver_string += ")."
1794
1795 f_name = acc_name(cls, m_name)
1796 out.write("""\
1797 * @param %(m_name)s_get/set %(ver_string)s
1798 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
1799 * are of type %(f_name)s_get_f and _set_f.
1800 *
1801""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
1802
1803 out.write("""\
1804 */
1805typedef struct %(cls)s_s %(cls)s_t;
1806""" % dict(cls=cls))
1807
1808 out.write("#endif /* _LOCI_DOC_H_ */\n")