blob: 484e94135692d6cd8957231afe578bdbf3fe0e94 [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];
406extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700407""")
Rich Lanea06d0c32013-03-25 08:52:03 -0700408 c_type_maps.gen_type_data_header(out)
409 c_match.gen_declarations(out)
410 # @fixme Move debug stuff to own fn
411 out.write("""
412/**
413 * Macro to check consistency of length for top level objects
414 *
415 * If the object has no parent then its length should match the
416 * underlying wire buffer's current bytes.
417 */
418#define OF_LENGTH_CHECK_ASSERT(obj) \\
Rich Lanee57f0432014-02-19 10:31:53 -0800419 LOCI_ASSERT(((obj)->parent != NULL) || \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700420 ((obj)->wbuf == NULL) || \\
421 (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
Rich Lanea06d0c32013-03-25 08:52:03 -0700422
423#define OF_DEBUG_DUMP
424#if defined(OF_DEBUG_DUMP)
425extern void dump_match(of_match_t *match);
426#endif /* OF_DEBUG_DUMP */
427""")
428
Rich Lane1f03f672014-08-05 00:10:00 -0700429 out.write("""
430static inline const char *
431of_class_name(of_object_t *obj)
432{
433 return of_object_id_str[obj->object_id];
434}
435""")
436
Rich Lanea06d0c32013-03-25 08:52:03 -0700437 out.write("\n#endif /* Top header file */\n")
438
439def match_c_gen(out, name):
440 """
441 Generate code for
442 @param out The file handle to write to
443 @param name The name of the file
444 """
445 c_match.match_c_top_matter(out, name)
446 c_match.gen_match_conversions(out)
447 c_match.gen_serialize(out)
448 c_match.gen_deserialize(out)
449
Rich Lanea06d0c32013-03-25 08:52:03 -0700450################################################################
451# Top Matter
452################################################################
453
454def common_top_matter(out, name):
455 loxi_utils.gen_c_copy_license(out)
456 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700457
Rich Lanea06d0c32013-03-25 08:52:03 -0700458/****************************************************************
459 * File: %s
460 *
461 * DO NOT EDIT
462 *
463 * This file is automatically generated
464 *
465 ****************************************************************/
466
467""" % name)
468
469 if name[-2:] == ".h":
470 out.write("""
471#if !defined(%(h)s)
472#define %(h)s
473
474""" % dict(h=h_file_to_define(name)))
475
476def base_h_content(out):
477 """
478 Generate base header file content
479
480 @param out The output file object
481 """
482
483 # @fixme Supported version should be generated based on input to LoxiGen
484
485 out.write("""
486/*
487 * Base OpenFlow definitions. These depend only on standard C headers
488 */
489#include <string.h>
490#include <stdint.h>
491
492/* g++ requires this to pick up PRI, etc.
493 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
494 */
495#if !defined(__STDC_FORMAT_MACROS)
496#define __STDC_FORMAT_MACROS
497#endif
498#include <inttypes.h>
499
500#include <stdlib.h>
501#include <assert.h>
502#include <loci/loci_idents.h>
503
504/**
505 * Macro to enable debugging for LOCI.
506 *
507 * This enables debug output to stdout.
508 */
509#define OF_DEBUG_ENABLE
510
511#if defined(OF_DEBUG_ENABLE)
512#include <stdio.h> /* Currently for debugging */
513#define FIXME(str) do { \\
514 fprintf(stderr, "%s\\n", str); \\
515 exit(1); \\
516 } while (0)
517#define debug printf
518#else
519#define FIXME(str)
520#define debug(str, ...)
521#endif /* OF_DEBUG_ENABLE */
522
523/**
524 * The type of a function used by the LOCI dump/show functions to
525 * output text. Essentially the same signature as fprintf. May
526 * be called many times per invocation of e.g. of_object_show().
527 */
528typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
529
530/**
531 * Check if a version is supported
532 */
533#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
534
535""")
536 gen_version_enum(out)
537 out.write("\n")
538
539 # for c_name in of_g.ofp_constants:
540 # val = str(of_g.ofp_constants[c_name])
541 # out.write("#define %s %s\n" % (c_name, val))
542 # out.write("\n")
543
544 out.write("""
545typedef enum of_error_codes_e {
546 OF_ERROR_NONE = 0,
547 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
548 OF_ERROR_PARAM = -2, /* Bad parameter */
549 OF_ERROR_VERSION = -3, /* Version not supported */
550 OF_ERROR_RANGE = -4, /* End of list indication */
551 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
552 OF_ERROR_PARSE = -6, /* Error in parsing data */
553 OF_ERROR_INIT = -7, /* Uninitialized data */
554 OF_ERROR_UNKNOWN = -8 /* Unknown error */
555} of_error_codes_t;
556
557#define OF_ERROR_STRINGS "none", \\
558 "resource", \\
559 "parameter", \\
560 "version", \\
561 "range", \\
562 "incompatible", \\
563 "parse", \\
564 "init", \\
565 "unknown"
566
Rich Laneb157b0f2013-03-27 13:55:28 -0700567extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700568
Rich Lanea8b54632014-02-19 11:17:47 -0800569#ifdef __GNUC__
570#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
571#else
572#define LOCI_NORETURN_ATTR
573#endif
574
575extern void loci_assert_fail(
576 const char *cond,
577 const char *file,
578 unsigned int line) LOCI_NORETURN_ATTR;
579
Rich Lane53757732013-02-23 17:00:10 -0800580#ifndef NDEBUG
Rich Lanea8b54632014-02-19 11:17:47 -0800581#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
Rich Lane53757732013-02-23 17:00:10 -0800582#else
Rich Lanee57f0432014-02-19 10:31:53 -0800583#define LOCI_ASSERT(val)
Rich Lane53757732013-02-23 17:00:10 -0800584#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700585
586/*
587 * Some LOCI object accessors can fail, and it's easy to forget to check.
588 * On certain compilers we can trigger a warning if the error code
589 * is ignored.
590 */
591#ifndef DISABLE_WARN_UNUSED_RESULT
592#ifdef __GNUC__
593#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
594#else
595#define WARN_UNUSED_RESULT
596#endif
597#else
598#define WARN_UNUSED_RESULT
599#endif
600
601typedef union of_generic_u of_generic_t;
602typedef struct of_object_s of_object_t;
603
604/* Define ipv4 address as uint32 */
605typedef uint32_t of_ipv4_t;
606
607/* Table ID is the OF standard uint8 */
608typedef uint8_t of_table_id_t;
609
610#define OF_MAC_ADDR_BYTES 6
611typedef struct of_mac_addr_s {
612 uint8_t addr[OF_MAC_ADDR_BYTES];
613} of_mac_addr_t;
614
615#define OF_IPV6_BYTES 16
616typedef struct of_ipv6_s {
617 uint8_t addr[OF_IPV6_BYTES];
618} of_ipv6_t;
619
620extern const of_mac_addr_t of_mac_addr_all_ones;
621extern const of_mac_addr_t of_mac_addr_all_zeros;
622
623extern const of_ipv6_t of_ipv6_all_ones;
624extern const of_ipv6_t of_ipv6_all_zeros;
625
626/**
627 * Generic zero and all-ones values of size 16 bytes.
628 *
629 * IPv6 is longest data type we worry about for comparisons
630 */
631#define of_all_zero_value of_ipv6_all_zeros
632#define of_all_ones_value of_ipv6_all_ones
633
634/**
635 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
636 */
637#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
638 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
639#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
640 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
641
642/* The octets object is a struct holding pointer and length */
643typedef struct of_octets_s {
644 uint8_t *data;
645 int bytes;
646} of_octets_t;
647
648/* Macro to convert an octet object to a pointer; currently trivial */
649#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
650#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
651#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
652#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
653
654/* Currently these are categorized as scalars */
655typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700656typedef char of_app_code_t[OF_APP_CODE_LEN];
Rich Lanea06d0c32013-03-25 08:52:03 -0700657typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
658typedef char of_desc_str_t[OF_DESC_STR_LEN];
659typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
Rich Lanef8a3d002014-03-19 13:33:52 -0700660typedef char of_str64_t[64];
Rich Lanea06d0c32013-03-25 08:52:03 -0700661
Rich Lane3b2fd832013-09-24 13:44:08 -0700662typedef struct of_bitmap_128_s {
663 uint64_t hi;
664 uint64_t lo;
665} of_bitmap_128_t;
666
Rich Lanefab0c822013-12-30 11:46:48 -0800667typedef struct of_checksum_128_s {
668 uint64_t hi;
669 uint64_t lo;
670} of_checksum_128_t;
671
Rich Lanea06d0c32013-03-25 08:52:03 -0700672/* These are types which change across versions. */
673typedef uint32_t of_port_no_t;
674typedef uint16_t of_fm_cmd_t;
675typedef uint64_t of_wc_bmap_t;
676typedef uint64_t of_match_bmap_t;
677
678#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
679#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
680#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
681#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
682#define MALLOC(bytes) malloc(bytes)
683#define FREE(ptr) free(ptr)
684
685/** Try an operation and return on failure. */
686#define OF_TRY(op) do { \\
687 int _rv; \\
688 if ((_rv = (op)) < 0) { \\
689 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
690 return _rv; \\
691 } \\
692 } while (0)
693
694/* The extent of an OF match object is determined by its length field, but
695 * aligned to 8 bytes
696 */
697
698#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
699
Rich Lanedfcafae2014-03-06 16:56:49 -0800700#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
Rich Lanea06d0c32013-03-25 08:52:03 -0700701#define U16_NTOH(val) (val)
702#define U32_NTOH(val) (val)
703#define U64_NTOH(val) (val)
704#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
705#define U16_HTON(val) (val)
706#define U32_HTON(val) (val)
707#define U64_HTON(val) (val)
708#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
709#else /* Little Endian */
Rich Lane69e247e2014-03-05 10:27:22 -0800710#define U16_NTOH(val) (((val) >> 8) | (((val) & 0xff) << 8))
Rich Lanea06d0c32013-03-25 08:52:03 -0700711#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
712 (((val) & 0x00ff0000) >> 8) | \\
713 (((val) & 0x0000ff00) << 8) | \\
714 (((val) & 0x000000ff) << 24))
715#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
716 (((val) & 0x00ff000000000000LL) >> 40) | \\
717 (((val) & 0x0000ff0000000000LL) >> 24) | \\
718 (((val) & 0x000000ff00000000LL) >> 8) | \\
719 (((val) & 0x00000000ff000000LL) << 8) | \\
720 (((val) & 0x0000000000ff0000LL) << 24) | \\
721 (((val) & 0x000000000000ff00LL) << 40) | \\
722 (((val) & 0x00000000000000ffLL) << 56))
723#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
724#define U16_HTON(val) U16_NTOH(val)
725#define U32_HTON(val) U32_NTOH(val)
726#define U64_HTON(val) U64_NTOH(val)
727#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
728#endif
729
730/****************************************************************
731 *
732 * The following are internal definitions used by the automatically
733 * generated code. Users should not reference these definitions
734 * as they may change between versions of this code
735 *
736 ****************************************************************/
737
738#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
739 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
740#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
741#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
742 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
743
744#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
745 (FIXED_LEN + of_message_out_actions_len_get(obj))
746
747""")
748
749def external_h_top_matter(out, name):
750 """
751 Generate top matter for external header file
752
753 @param name The name of the output file
754 @param out The output file object
755 """
756 common_top_matter(out, name)
757 out.write("""
758#include <loci/loci_base.h>
759#include <loci/of_message.h>
760#include <loci/of_match.h>
761#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800762#include <loci/loci_classes.h>
Rich Lanedc46fe22014-04-03 15:10:38 -0700763#include <loci/loci_class_metadata.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700764
765/****************************************************************
766 *
767 * This file is divided into the following sections.
768 *
769 * A few object specific macros
770 * Class typedefs (no struct definitions)
771 * Per-data type accessor function typedefs
772 * Per-class new/delete function typedefs
773 * Per-class static delete functions
774 * Per-class, per-member accessor declarations
775 * Per-class structure definitions
776 * Generic union (inheritance) definitions
777 * Pointer set function declarations
778 * Some special case macros
779 *
780 ****************************************************************/
781""")
782
Rich Lanea06d0c32013-03-25 08:52:03 -0700783################################################################
784#
785################################################################
786
787def gen_version_enum(out):
788 """
789 Generate the enumerated type for versions in LoxiGen
790 @param out The file object to which to write the decs
791
792 This just uses the wire versions for now
793 """
794 out.write("""
795/**
796 * Enumeration of OpenFlow versions
797 *
798 * The wire protocol numbers are currently used for values of the corresponding
799 * version identifiers.
800 */
801typedef enum of_version_e {
802 OF_VERSION_UNKNOWN = 0,
803""")
804
805 is_first = True
806 max = 0
807 for v in of_g.wire_ver_map:
808 if is_first:
809 is_first = False
810 else:
811 out.write(",\n")
812 if v > max:
813 max = v
814 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
815
816 out.write("""
817} of_version_t;
818
819/**
820 * @brief Use this when declaring arrays indexed by wire version
821 */
822#define OF_VERSION_ARRAY_MAX %d
823""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700824
Rich Lanea06d0c32013-03-25 08:52:03 -0700825def gen_object_enum(out):
826 """
827 Generate the enumerated type for object identification in LoxiGen
828 @param out The file object to which to write the decs
829 """
830 out.write("""
831
832/**
833 * Enumeration of OpenFlow objects
834 *
835 * We enumerate the OpenFlow objects used internally. Note that some
836 * message types are determined both by an outer type (message type like
837 * stats_request) and an inner type (port stats). These are different
838 * messages in ofC.
839 *
840 * These values are for internal use only. They will change with
841 * different versions of ofC.
842 */
843
844typedef enum of_object_id_e {
845 /* Root object type */
846 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
847 OF_OBJECT = 0, /* Generic, untyped object */
848
849 /* OpenFlow message objects */
850""")
851 last = 0
852 msg_count = 0
853 for cls in of_g.ordered_messages:
854 out.write(" %s = %d,\n" % (enum_name(cls),
855 of_g.unified[cls]["object_id"]))
856 msg_count = of_g.unified[cls]["object_id"] + 1
857
858 out.write("\n /* Non-message objects */\n")
859 for cls in of_g.ordered_non_messages:
860 out.write(" %s = %d,\n" % (enum_name(cls),
861 of_g.unified[cls]["object_id"]))
862 last = of_g.unified[cls]["object_id"]
863 out.write("\n /* List objects */\n")
864 for cls in of_g.ordered_list_objects:
865 out.write(" %s = %d,\n" % (enum_name(cls),
866 of_g.unified[cls]["object_id"]))
867 last = of_g.unified[cls]["object_id"]
868
Rich Lanea06d0c32013-03-25 08:52:03 -0700869 out.write("""
870 OF_OBJECT_COUNT = %d
871} of_object_id_t;
872
Rich Laneb157b0f2013-03-27 13:55:28 -0700873extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700874
875#define OF_MESSAGE_OBJECT_COUNT %d
876""" % ((last + 1), msg_count))
877
878 # Generate object type range checking for inheritance classes
879
880 # @fixme These should be determined algorithmicly
881 out.write("""
882/*
883 * Macros to check if an object ID is within an inheritance class range
884 */
885""")
886 # Alphabetical order for 'last'
887 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
888 of_oxm="OF_OXM_VLAN_VID_MASKED",
889 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
890 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
891 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
892 # @FIXME add meter_band ?
893 )
894 for cls, last in last_ids.items():
895 out.write("""
896#define %(enum)s_FIRST_ID (%(enum)s + 1)
897#define %(enum)s_LAST_ID %(last)s
898#define %(enum)s_VALID_ID(id) \\
899 ((id) >= %(enum)s_FIRST_ID && \\
900 (id) <= %(enum)s_LAST_ID)
901""" % dict(enum=enum_name(cls), last=last))
902 out.write("""
903/**
904 * Function to check a wire ID
905 * @param object_id The ID to check
906 * @param base_object_id The inheritance parent, if applicable
907 * @returns boolean: If base_object_id is an inheritance class, check if
908 * object_id is valid as a subclass. Otherwise return 1.
909 *
910 * Note: Could check that object_id == base_object_id in the
911 * second case.
912 */
913static inline int
914of_wire_id_valid(int object_id, int base_object_id) {
915 switch (base_object_id) {
916 case OF_ACTION:
917 return OF_ACTION_VALID_ID(object_id);
918 case OF_OXM:
919 return OF_OXM_VALID_ID(object_id);
920 case OF_QUEUE_PROP:
921 return OF_QUEUE_PROP_VALID_ID(object_id);
922 case OF_TABLE_FEATURE_PROP:
923 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
924 case OF_INSTRUCTION:
925 return OF_INSTRUCTION_VALID_ID(object_id);
926 default:
927 break;
928 }
929 return 1;
930}
931""")
932
Rich Lanea06d0c32013-03-25 08:52:03 -0700933################################################################
934#
935# Internal Utility Functions
936#
937################################################################
938
939
940def acc_name(cls, m_name):
941 """
942 Generate the root name of an accessor function for typedef
943 @param cls The class name
944 @param m_name The member name
945 """
946 (m_type, get_rv) = get_acc_rv(cls, m_name)
947 return "%s_%s" % (cls, m_type)
948
949def get_acc_rv(cls, m_name):
950 """
951 Determine the data type and return type for a get accessor.
952
953 The return type may be "void" or it may be the accessor type
954 depending on the system configuration and on the data type.
955
956 @param cls The class name
957 @param m_name The member name
958 @return A pair (m_type, rv) where m_type is the unified type of the
959 member and rv is the get_accessor return type
960 """
961 member = of_g.unified[cls]["union"][m_name]
962 m_type = member["m_type"]
963 rv = "int"
Rich Lanea06d0c32013-03-25 08:52:03 -0700964 if m_type[-2:] == "_t":
965 m_type = m_type[:-2]
966
967 return (m_type, rv)
968
969def param_list(cls, m_name, a_type):
970 """
971 Generate the parameter list (no parens) for an a_type accessor
972 @param cls The class name
973 @param m_name The member name
974 @param a_type One of "set" or "get" or TBD
975 """
976 member = of_g.unified[cls]["union"][m_name]
977 m_type = member["m_type"]
978 params = ["%s_t *obj" % cls]
979 if a_type == "set":
980 if loxi_utils.type_is_scalar(m_type):
981 params.append("%s %s" % (m_type, m_name))
982 else:
983 params.append("%s *%s" % (m_type, m_name))
984 elif a_type in ["get", "bind"]:
985 params.append("%s *%s" % (m_type, m_name))
986 else:
987 debug("Class %s, name %s Bad param list a_type: %s" %
988 (cls, m_name, a_type))
989 sys.exit(1)
990 return params
991
Rich Lanea06d0c32013-03-25 08:52:03 -0700992def field_ver_get(cls, m_name):
993 """
994 Generate a dict, indexed by wire version, giving a pair (type, offset)
995
996 @param cls The class name
997 @param m_name The name of the class member
998
999 If offset is not known for m_name, the type
1000 A dict is used for more convenient indexing.
1001 """
1002 result = {}
1003
1004 for ver in of_g.unified[cls]:
1005 if type(ver) == type(0): # It's a version
1006 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1007 ref_ver = of_g.unified[cls][ver]["use_version"]
1008 members = of_g.unified[cls][ref_ver]["members"]
1009 else:
1010 members = of_g.unified[cls][ver]["members"]
1011 idx = loxi_utils.member_to_index(m_name, members)
1012 if (idx < 0):
1013 continue # Member not in this version
1014 m_type = members[idx]["m_type"]
1015 offset = members[idx]["offset"]
1016
1017 # If m_type is mixed, get wire version type from global data
1018 if m_type in of_g.of_mixed_types and \
1019 ver in of_g.of_mixed_types[m_type]:
1020 m_type = of_g.of_mixed_types[m_type][ver]
1021
1022 # add version to result list
1023 result[ver] = (m_type, offset)
1024
1025 return result
1026
1027def v3_match_offset_get(cls):
1028 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001029 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001030 otherwise return -1
1031 """
1032 result = field_ver_get(cls, "match")
1033 if of_g.VERSION_1_2 in result:
1034 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1035 return result[of_g.VERSION_1_2][1]
1036 return -1
1037
1038################################################################
1039#
1040# OpenFlow Object Definitions
1041#
1042################################################################
1043
Rich Lanea06d0c32013-03-25 08:52:03 -07001044def gen_generics(out):
1045 for (cls, subclasses) in type_maps.inheritance_map.items():
1046 out.write("""
1047/**
1048 * Inheritance super class for %(cls)s
1049 *
1050 * This class is the union of %(cls)s classes. You can refer
1051 * to it untyped by refering to the member 'header' whose structure
1052 * is common across all sub-classes.
1053 */
1054
1055union %(cls)s_u {
1056 %(cls)s_header_t header; /* Generic instance */
1057""" % dict(cls=cls))
1058 for subcls in sorted(subclasses):
1059 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1060 out.write("};\n")
1061
1062def gen_struct_typedefs(out):
1063 """
1064 Generate typedefs for all struct objects
1065 @param out The file for output, already open
1066 """
1067
1068 out.write("\n/* LOCI inheritance parent typedefs */\n")
1069 for cls in type_maps.inheritance_map:
1070 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1071 out.write("\n/* LOCI object typedefs */\n")
1072 for cls in of_g.standard_class_order:
1073 if cls in type_maps.inheritance_map:
1074 continue
Rich Lane85767872013-12-15 16:24:42 -08001075 template = "typedef of_object_t %(cls)s_t;\n"
1076 out.write(template % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001077
1078 out.write("""
1079/****************************************************************
1080 *
1081 * Additional of_object defines
1082 * These are needed for some static inline ops, so we put them here.
1083 *
1084 ****************************************************************/
1085
1086/* Delete an OpenFlow object without reference to its type */
1087extern void of_object_delete(of_object_t *obj);
1088
1089""")
1090
Rich Lanea06d0c32013-03-25 08:52:03 -07001091################################################################
1092#
Rich Lanea06d0c32013-03-25 08:52:03 -07001093# Accessor Functions
1094#
1095################################################################
1096
Andreas Wundsam53256162013-05-02 14:05:53 -07001097
Rich Lanea06d0c32013-03-25 08:52:03 -07001098def gen_accessor_declarations(out):
1099 """
1100 Generate the declaration of each version independent accessor
1101
1102 @param out The file to which to write the decs
1103 """
1104
1105 out.write("""
1106/****************************************************************
1107 *
1108 * Unified, per-member accessor function declarations
1109 *
1110 ****************************************************************/
1111""")
1112 for cls in of_g.standard_class_order:
1113 if cls in type_maps.inheritance_map:
1114 continue
1115 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1116 for m_name in of_g.ordered_members[cls]:
1117 if m_name in of_g.skip_members:
1118 continue
1119 m_type = loxi_utils.member_base_type(cls, m_name)
1120 base_name = "%s_%s" % (cls, m_name)
1121 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1122 get_ret_type = accessor_return_type("get", m_type)
1123 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1124 set_ret_type = accessor_return_type("set", m_type)
1125 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1126 bind_ret_type = accessor_return_type("bind", m_type)
1127
1128 if loxi_utils.type_is_of_object(m_type):
1129 # Generate bind accessors, but not get accessor
1130 out.write("""
1131extern %(set_ret_type)s %(base_name)s_set(
1132 %(sparams)s);
1133extern %(bind_ret_type)s %(base_name)s_bind(
1134 %(bparams)s);
1135extern %(m_type)s *%(cls)s_%(m_name)s_get(
1136 %(cls)s_t *obj);
1137""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1138 m_name=m_name, m_type=m_type, cls=cls,
1139 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1140 else:
1141 out.write("""
1142extern %(set_ret_type)s %(base_name)s_set(
1143 %(sparams)s);
1144extern %(get_ret_type)s %(base_name)s_get(
1145 %(gparams)s);
1146""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1147 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001148
Rich Lanea06d0c32013-03-25 08:52:03 -07001149 if loxi_utils.class_is_list(cls):
1150 e_type = loxi_utils.list_to_entry_type(cls)
1151 out.write("""
1152extern int %(cls)s_first(
1153 %(cls)s_t *list, %(e_type)s_t *obj);
1154extern int %(cls)s_next(
1155 %(cls)s_t *list, %(e_type)s_t *obj);
1156extern int %(cls)s_append_bind(
1157 %(cls)s_t *list, %(e_type)s_t *obj);
1158extern int %(cls)s_append(
1159 %(cls)s_t *list, %(e_type)s_t *obj);
1160
1161/**
1162 * Iteration macro for list of type %(cls)s
1163 * @param list Pointer to the list being iterated over of
1164 * type %(cls)s
1165 * @param elt Pointer to an element of type %(e_type)s
1166 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1167 */
1168#define %(u_cls)s_ITER(list, elt, rv) \\
1169 for ((rv) = %(cls)s_first((list), (elt)); \\
1170 (rv) == OF_ERROR_NONE; \\
1171 (rv) = %(cls)s_next((list), (elt)))
1172""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1173
1174
1175def wire_accessor(m_type, a_type):
1176 """
1177 Returns the name of the a_type accessor for low level wire buff offset
1178 @param m_type The member type
1179 @param a_type The accessor type (set or get)
1180 """
1181 # Strip off _t if present
1182 if m_type in of_g.of_base_types:
1183 m_type = of_g.of_base_types[m_type]["short_name"]
1184 if m_type in of_g.of_mixed_types:
1185 m_type = of_g.of_mixed_types[m_type]["short_name"]
1186 if m_type[-2:] == "_t":
1187 m_type = m_type[:-2]
1188 if m_type == "octets":
1189 m_type = "octets_data"
1190 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1191
Rich Lane713d9282013-12-30 15:21:35 -08001192def get_len_macro(cls, m_name, m_type, version):
Rich Lanea06d0c32013-03-25 08:52:03 -07001193 """
1194 Get the length macro for m_type in cls
1195 """
1196 if m_type.find("of_match") == 0:
1197 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1198 if m_type.find("of_list_oxm") == 0:
1199 return "wire_match_len(obj, 0) - 4"
1200 if loxi_utils.class_is_tlv16(m_type):
1201 return "_TLV16_LEN(obj, offset)"
1202 if cls == "of_packet_out" and m_type == "of_list_action_t":
1203 return "_PACKET_OUT_ACTION_LEN(obj)"
Rich Lane713d9282013-12-30 15:21:35 -08001204 if cls == "of_bsn_gentable_entry_add" and m_name == "key":
1205 return "of_object_u16_get(obj, 18)"
1206 if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
1207 return "of_object_u16_get(obj, 2)"
1208 if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
1209 return "of_object_u16_get(obj, 2)"
Rich Lanea06d0c32013-03-25 08:52:03 -07001210 # Default is everything to the end of the object
1211 return "_END_LEN(obj, offset)"
1212
1213def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1214 """
1215 Generate the sub-object offset and length calculations for accessors
1216 @param out File being written
1217 @param m_name Name of member
1218 @param version Wire version being processed
1219 @param a_type The accessor type (set or get)
1220 @param m_type The original member type
1221 @param offset The offset of the object or -1 if not fixed
1222 """
1223 # determine offset
1224 o_str = "%d" % offset # Default is fixed length
1225 if offset == -1:
1226 # There are currently 4 special cases for this
1227 # In general, get offset and length of predecessor
1228 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1229 pass
1230 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1231 pass
1232 elif (cls == "of_packet_in" and m_name == "data"):
1233 pass
1234 elif (cls == "of_packet_out" and m_name == "data"):
1235 pass
Rich Lane713d9282013-12-30 15:21:35 -08001236 elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
1237 pass
1238 elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
1239 pass
1240 elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
1241 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001242 else:
1243 debug("Error: Unknown member with offset == -1")
1244 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1245 sys.exit(1)
1246 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1247
1248 out.write("""\
1249 offset = %s;
1250""" % o_str);
1251
1252 # This could be moved to main body but for version check
1253 if not loxi_utils.type_is_scalar(m_type):
1254 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1255 m_type == "of_match_t":
Rich Lane713d9282013-12-30 15:21:35 -08001256 len_macro = get_len_macro(cls, m_name, m_type, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001257 else:
1258 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1259 out.write(" cur_len = %s;\n" % len_macro)
1260 out.write(" break;\n")
1261
1262def length_of(m_type, version):
1263 """
1264 Return the length of a type based on the version
1265 """
1266 if m_type in of_g.of_mixed_types:
1267 m_type = of_g.of_mixed_types[m_type][version]
1268 if m_type in of_g.of_base_types:
1269 return of_g.of_base_types[m_type]["bytes"]
1270 if (m_type[:-2], version) in of_g.base_length:
1271 return of_g.base_length[(m_type[:-2], version)]
1272 print "Unknown length request", m_type, version
1273 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001274
Rich Lanea06d0c32013-03-25 08:52:03 -07001275
1276def gen_get_accessor_body(out, cls, m_type, m_name):
1277 """
1278 Generate the common operations for a get accessor
1279 """
1280 if loxi_utils.type_is_scalar(m_type):
1281 ver = "" # See if version required for scalar update
1282 if m_type in of_g.of_mixed_types:
1283 ver = "ver, "
1284 out.write("""\
1285 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1286""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1287
1288 if m_type == "of_port_no_t":
1289 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1290 elif m_type == "of_octets_t":
1291 out.write("""\
Rich Lanee57f0432014-02-19 10:31:53 -08001292 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001293 %(m_name)s->bytes = cur_len;
1294 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1295""" % dict(m_name=m_name))
1296 elif m_type == "of_match_t":
1297 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001298 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanee0b70cc2014-06-12 15:02:22 -07001299 OF_TRY(of_match_deserialize(ver, %(m_name)s, obj, offset, cur_len));
Rich Lanea06d0c32013-03-25 08:52:03 -07001300""" % dict(m_name=m_name))
Rich Lane90020b42014-04-07 12:05:45 -07001301 elif m_type == "of_oxm_header_t":
1302 out.write("""
1303 /* Initialize child */
1304 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1305 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001306 of_object_attach(obj, %(m_name)s, offset, cur_len);
Rich Lane90020b42014-04-07 12:05:45 -07001307 of_object_wire_init(%(m_name)s, OF_OXM, 0);
1308""" % dict(m_type=m_type[:-2], m_name=m_name))
Wilson Ngd6181882014-04-14 16:28:35 -07001309 elif m_type == "of_bsn_vport_header_t":
1310 out.write("""
1311 /* Initialize child */
1312 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1313 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001314 of_object_attach(obj, %(m_name)s, offset, cur_len);
Wilson Ngd6181882014-04-14 16:28:35 -07001315 of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
1316""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001317 else:
1318 out.write("""
1319 /* Initialize child */
1320 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1321 /* Attach to parent */
Rich Laned1fe6972014-06-12 14:53:24 -07001322 of_object_attach(obj, %(m_name)s, offset, cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001323""" % dict(m_type=m_type[:-2], m_name=m_name))
1324
1325
1326def gen_set_accessor_body(out, cls, m_type, m_name):
1327 """
1328 Generate the contents of a set accessor
1329 """
1330 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1331 ver = "" # See if version required for scalar update
1332 if m_type in of_g.of_mixed_types:
1333 ver = "ver, "
1334 cur_len = "" # See if version required for scalar update
1335 if m_type == "of_octets_t":
1336 cur_len = ", cur_len"
1337 out.write("""\
1338 new_len = %(m_name)s->bytes;
1339 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1340""" % dict(m_name=m_name))
1341 out.write("""\
1342 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1343""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1344 m_name=m_name))
1345
1346 elif m_type == "of_match_t":
1347 out.write("""
Rich Lanee0b70cc2014-06-12 15:02:22 -07001348 {
1349 /* Match object */
1350 of_octets_t match_octets;
1351 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1352 new_len = match_octets.bytes;
1353 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1354 match_octets.data, new_len);
1355 /* Free match serialized octets */
1356 FREE(match_octets.data);
1357 }
Rich Lanea06d0c32013-03-25 08:52:03 -07001358""" % dict(m_name=m_name))
1359
1360 else: # Other object type
1361 out.write("\n /* LOCI object type */")
1362 # Need to special case OXM list
1363 out.write("""
1364 new_len = %(m_name)s->length;
1365 /* If underlying buffer already shared; nothing to do */
Rich Lanecdd542d2014-04-03 16:13:12 -07001366 if (obj->wbuf == %(m_name)s->wbuf) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001367 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1368 /* Verify that the offsets are correct */
Rich Lanee57f0432014-02-19 10:31:53 -08001369 LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1370 /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
Rich Lanea06d0c32013-03-25 08:52:03 -07001371 return %(ret_success)s;
1372 }
1373
1374 /* Otherwise, replace existing object in data buffer */
1375 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1376 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1377""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1378
1379 if not loxi_utils.type_is_scalar(m_type):
1380 if cls == "of_packet_out" and m_type == "of_list_action_t":
1381 out.write("""
1382 /* Special case for setting action lengths */
1383 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1384""" % dict(m_name=m_name))
Rich Lane713d9282013-12-30 15:21:35 -08001385 elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
1386 out.write("""
1387 /* Special case for setting key length */
1388 of_object_u16_set(obj, 18, %(m_name)s->length);
1389""" % dict(m_name=m_name))
1390 elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
1391 out.write("""
1392 /* Special case for setting key length */
1393 of_object_u16_set(obj, 2, %(m_name)s->length);
1394""" % dict(m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001395 elif m_type not in ["of_match_t", "of_octets_t"]:
1396 out.write("""
1397 /* @fixme Shouldn't this precede copying value's data to buffer? */
Rich Lanedc46fe22014-04-03 15:10:38 -07001398 of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001399""" % dict(m_name=m_name))
1400 out.write("""
1401 /* Not scalar, update lengths if needed */
1402 delta = new_len - cur_len;
1403 if (delta != 0) {
1404 /* Update parent(s) */
1405 of_object_parent_length_update((of_object_t *)obj, delta);
1406 }
1407""")
1408
1409def obj_assert_check(cls):
1410 """
1411 The body of the assert check for an accessor
1412 We allow all versions of add/delete/modify to use the same accessors
1413 """
1414 if cls in ["of_flow_modify", "of_flow_modify_strict",
1415 "of_flow_delete", "of_flow_delete_strict",
1416 "of_flow_add"]:
1417 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1418 else:
1419 return "obj->object_id == %s" % cls.upper()
1420
1421def gen_of_object_get(out, cls, m_name, m_type):
1422 sub_cls = m_type[:-2]
1423 out.write("""
1424/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001425 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001426 * a %(cls)s instance.
1427 *
1428 * @param obj Pointer to the source of type %(cls)s_t
1429 * @returns A pointer to a new instance of type %(m_type)s whose contents
1430 * match that of %(m_name)s from source
1431 * @returns NULL if an error occurs
1432 */
1433%(m_type)s *
1434%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1435 %(m_type)s _%(m_name)s;
1436 %(m_type)s *_%(m_name)s_ptr;
1437
1438 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1439 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1440 return _%(m_name)s_ptr;
1441}
1442""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1443
1444def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1445 """
1446 Generate the body of a set or get accessor function
1447
1448 @param out The file to which to write the decs
1449 @param cls The class name
1450 @param m_name The member name
1451 @param ver_type_map Maps (type, offset) pairs to a list of versions
1452 @param a_type The accessor type, set or get
1453 @param m_type The original member type
1454
1455 The type values in ver_type_map are now ignored as we've pushed down
1456 the type munging to the lower level.
1457
1458 This is unified because the version switch case processing is the
1459 same for both set and get
1460 """
1461 out.write("""{
1462 of_wire_buffer_t *wbuf;
1463 int offset = 0; /* Offset of value relative to the start obj */
1464 int abs_offset; /* Offset of value relative to start of wbuf */
1465 of_version_t ver;
1466""")
1467
1468 if not loxi_utils.type_is_scalar(m_type):
1469 out.write("""\
1470 int cur_len = 0; /* Current length of object data */
1471""")
1472 if a_type == "set":
1473 out.write("""\
1474 int new_len, delta; /* For set, need new length and delta */
1475""")
1476
Rich Lanea06d0c32013-03-25 08:52:03 -07001477 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001478 LOCI_ASSERT(%(assert_str)s);
Rich Lanea06d0c32013-03-25 08:52:03 -07001479 ver = obj->version;
1480 wbuf = OF_OBJECT_TO_WBUF(obj);
Rich Lanee57f0432014-02-19 10:31:53 -08001481 LOCI_ASSERT(wbuf != NULL);
Rich Lanea06d0c32013-03-25 08:52:03 -07001482
1483 /* By version, determine offset and current length (where needed) */
1484 switch (ver) {
1485""" % dict(assert_str=obj_assert_check(cls)))
1486
1487 for first in sorted(ver_type_map):
1488 (prev_t, prev_o) = ver_type_map[first]
1489 prev_len = length_of(prev_t, first)
1490 prev = first
1491 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1492 break
1493
1494 for next in sorted(ver_type_map):
1495 if next == first:
1496 continue
1497
1498 (t, o) = ver_type_map[next]
1499 cur_len = length_of(t, next)
1500 if o == prev_o and cur_len == prev_len:
1501 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1502 continue
1503 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1504 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1505 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1506
1507 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1508 out.write("""\
1509 default:
Rich Lanee57f0432014-02-19 10:31:53 -08001510 LOCI_ASSERT(0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001511 }
1512
1513 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
Rich Lanee57f0432014-02-19 10:31:53 -08001514 LOCI_ASSERT(abs_offset >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001515""")
1516 if not loxi_utils.type_is_scalar(m_type):
Rich Lanee57f0432014-02-19 10:31:53 -08001517 out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001518
1519 # Now generate the common accessor code
1520 if a_type in ["get", "bind"]:
1521 gen_get_accessor_body(out, cls, m_type, m_name)
1522 else:
1523 gen_set_accessor_body(out, cls, m_type, m_name)
1524
1525 out.write("""
1526 OF_LENGTH_CHECK_ASSERT(obj);
1527
1528 return %s;
1529}
1530""" % accessor_return_success(a_type, m_type))
1531
1532def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1533 """
1534 For generating the bind call for OF sub-objects
1535 """
1536
1537 params = ",\n ".join(param_list(cls, m_name, "bind"))
1538 out.write("""
1539/**
1540 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1541 * member %(m_name)s
1542 * @param obj Pointer to an object of type %(cls)s.
1543 * @param %(m_name)s Pointer to the child object of type
1544 * %(m_type)s to be filled out.
1545 * \ingroup %(cls)s
1546 *
1547 * The parameter %(m_name)s is filled out to point to the same underlying
1548 * wire buffer as its parent.
1549 *
1550 */
1551""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1552
1553 ret_type = accessor_return_type("bind", m_type)
1554 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1555 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1556
1557def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
1558 """
1559 For generating the get call for non- OF sub-objects
1560 """
1561 params = ",\n ".join(param_list(cls, m_name, "get"))
1562 out.write("""
1563/**
1564 * Get %(m_name)s from an object of type %(cls)s.
1565 * @param obj Pointer to an object of type %(cls)s.
1566 * @param %(m_name)s Pointer to the child object of type
1567 * %(m_type)s to be filled out.
1568 *
1569 */
1570""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1571
1572 ret_type = accessor_return_type("get", m_type)
1573 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
1574 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
1575
Rich Lanece2e4642013-12-15 12:05:45 -08001576def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001577 for m_name in of_g.ordered_members[cls]:
1578 if m_name in of_g.skip_members:
1579 continue
1580 m_type = loxi_utils.member_base_type(cls, m_name)
1581 ver_type_map = field_ver_get(cls, m_name)
1582
1583 # Generate get/bind pending on member type
1584 # FIXME: Does this do the right thing for match?
1585 if loxi_utils.type_is_of_object(m_type):
1586 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
1587 gen_of_object_get(out, cls, m_name, m_type)
1588 else:
1589 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
1590
1591 # Now generate set accessor for all objects
1592 params = ",\n ".join(param_list(cls, m_name, "set"))
1593 out.write("""
1594/**
1595 * Set %(m_name)s in an object of type %(cls)s.
1596 * @param obj Pointer to an object of type %(cls)s.
1597""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1598 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1599 out.write("""\
1600 * @param %(m_name)s The value to write into the object
1601 */
1602""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1603 else:
1604 out.write("""\
1605 * @param %(m_name)s Pointer to the child of type %(m_type)s.
1606 *
1607 * If the child's wire buffer is the same as the parent's, then
1608 * nothing is done as the changes have already been registered in the
1609 * parent. Otherwise, the data in the child's wire buffer is inserted
1610 * into the parent's and the appropriate lengths are updated.
1611 */
1612""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1613 ret_type = accessor_return_type("set", m_type)
1614 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
1615 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
1616
Rich Lanea06d0c32013-03-25 08:52:03 -07001617################################################################
1618#
1619# New/Delete Function Definitions
1620#
1621################################################################
1622
Rich Lanea06d0c32013-03-25 08:52:03 -07001623################################################################
1624# Routines to generate the body of new/delete functions
1625################################################################
1626
1627def gen_init_fn_body(cls, out):
1628 """
1629 Generate function body for init function
1630 @param cls The class name for the function
1631 @param out The file to which to write
1632 """
1633 if cls in type_maps.inheritance_map:
1634 param = "obj_p"
1635 else:
1636 param = "obj"
1637
1638 out.write("""
1639/**
1640 * Initialize an object of type %(cls)s.
1641 *
1642 * @param obj Pointer to the object to initialize
1643 * @param version The wire version to use for the object
1644 * @param bytes How many bytes in the object
1645 * @param clean_wire Boolean: If true, clear the wire object control struct
1646 *
1647 * If bytes < 0, then the default fixed length is used for the object
1648 *
1649 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07001650 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07001651 *
1652 * If anything other than 0 is passed in for the buffer size, the underlying
1653 * wire buffer will have 'grow' called.
1654 */
1655
1656void
1657%(cls)s_init(%(cls)s_t *%(param)s,
1658 of_version_t version, int bytes, int clean_wire)
1659{
1660""" % dict(cls=cls, param=param))
1661
1662 # Use an extra pointer to deal with inheritance classes
1663 if cls in type_maps.inheritance_map:
1664 out.write("""\
1665 %s_header_t *obj;
1666
1667 obj = &obj_p->header; /* Need instantiable subclass */
1668""" % cls)
1669
1670 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001671 LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001672 if (clean_wire) {
1673 MEMSET(obj, 0, sizeof(*obj));
1674 }
1675 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07001676 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001677 }
1678 obj->version = version;
1679 obj->length = bytes;
1680 obj->object_id = %(enum)s;
1681""" % dict(cls=cls, enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001682
1683 out.write("""
1684 /* Grow the wire buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -07001685 if (obj->wbuf != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001686 int tot_bytes;
1687
Rich Lanecdd542d2014-04-03 16:13:12 -07001688 tot_bytes = bytes + obj->obj_offset;
1689 of_wire_buffer_grow(obj->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -07001690 }
1691}
1692
1693""")
1694
1695## @fixme This should also be updated once there is a map from
1696# class instance to wire length/type accessors
1697def gen_wire_push_fn(cls, out):
1698 """
1699 Generate the calls to push values into the wire buffer
1700 """
1701 if type_maps.class_is_virtual(cls):
1702 print "Push fn gen called for virtual class " + cls
1703 return
1704
1705 out.write("""
1706/**
1707 * Helper function to push values into the wire buffer
1708 */
1709static inline int
1710%(cls)s_push_wire_values(%(cls)s_t *obj)
1711{
1712""" % dict(cls=cls))
1713
Rich Lanebdd8e292013-12-06 17:37:39 -08001714 import loxi_globals
1715 uclass = loxi_globals.unified.class_by_name(cls)
1716 if uclass and not uclass.virtual and uclass.has_type_members:
1717 out.write("""
1718 %(cls)s_push_wire_types(obj);
1719""" % dict(cls=cls))
1720
Rich Lanea06d0c32013-03-25 08:52:03 -07001721 if loxi_utils.class_is_message(cls):
1722 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08001723 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07001724 of_message_t msg;
1725
1726 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001727 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001728 }
1729""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07001730
Rich Lanea06d0c32013-03-25 08:52:03 -07001731 else: # Not a message
1732 if loxi_utils.class_is_tlv16(cls):
1733 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08001734 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07001735 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001736""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001737
Rich Lanea06d0c32013-03-25 08:52:03 -07001738 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
1739 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001740 of_object_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001741""")
1742
1743 if cls == "of_meter_stats":
1744 out.write("""
1745 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
1746""" % dict(enum=enum_name(cls)))
1747
1748 out.write("""
1749 return OF_ERROR_NONE;
1750}
1751""")
1752
1753def gen_new_fn_body(cls, out):
1754 """
1755 Generate function body for new function
1756 @param cls The class name for the function
1757 @param out The file to which to write
1758 """
1759
1760 out.write("""
1761/**
1762 * \\defgroup %(cls)s %(cls)s
1763 */
1764""" % dict(cls=cls))
1765
1766 if not type_maps.class_is_virtual(cls):
1767 gen_wire_push_fn(cls, out)
1768
Rich Lane37911fd2014-04-01 22:11:22 -07001769 uclass = loxi_globals.unified.class_by_name(cls)
1770 is_fixed_length = uclass and uclass.is_fixed_length
1771 max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
1772
Rich Lanea06d0c32013-03-25 08:52:03 -07001773 out.write("""
1774/**
1775 * Create a new %(cls)s object
1776 *
1777 * @param version The wire version to use for the object
1778 * @return Pointer to the newly create object or NULL on error
1779 *
1780 * Initializes the new object with it's default fixed length associating
1781 * a new underlying wire buffer.
1782 *
Rich Lanea06d0c32013-03-25 08:52:03 -07001783 * \\ingroup %(cls)s
1784 */
1785
1786%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08001787%(cls)s_new(of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001788{
1789 %(cls)s_t *obj;
1790 int bytes;
1791
Rich Lanef70be942013-07-18 13:33:14 -07001792 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001793
Rich Lane37911fd2014-04-01 22:11:22 -07001794 if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001795 return NULL;
1796 }
1797
1798 %(cls)s_init(obj, version, bytes, 0);
Rich Lane37911fd2014-04-01 22:11:22 -07001799""" % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
Rich Lanea06d0c32013-03-25 08:52:03 -07001800 if not type_maps.class_is_virtual(cls):
1801 out.write("""
1802 if (%(cls)s_push_wire_values(obj) < 0) {
1803 FREE(obj);
1804 return NULL;
1805 }
1806""" % dict(cls=cls))
1807
1808 match_offset = v3_match_offset_get(cls)
1809 if match_offset >= 0:
1810 # Init length field for match object
1811 out.write("""
1812 /* Initialize match TLV for 1.2 */
1813 /* FIXME: Check 1.3 below */
1814 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
1815 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
1816 }
1817""" % dict(match_offset=match_offset))
1818 out.write("""
1819 return obj;
1820}
Rich Lanea06d0c32013-03-25 08:52:03 -07001821""" % dict(cls=cls))
1822
1823
Rich Lanea06d0c32013-03-25 08:52:03 -07001824################################################################
1825# Now the top level generator functions
1826################################################################
1827
1828def gen_new_function_declarations(out):
1829 """
1830 Gerenate the header file declarations for new operators for all classes
1831 @param out The file to which to write the decs
1832 """
1833
1834 out.write("""
1835/****************************************************************
1836 *
1837 * New operator declarations
1838 *
1839 * _new: Create a new object for writing; includes init
Rich Lanea06d0c32013-03-25 08:52:03 -07001840 * _init: Initialize and optionally allocate buffer space for an
1841 * automatic instance
1842 *
Rich Lanebb8f17c2014-06-12 13:14:09 -07001843 * _new and requires a delete operation to be called on the object.
Rich Lanea06d0c32013-03-25 08:52:03 -07001844 *
1845 ****************************************************************/
1846""")
Rich Lanea06d0c32013-03-25 08:52:03 -07001847
1848 for cls in of_g.standard_class_order:
1849 out.write("""
1850extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08001851 %(cls)s_new(of_version_t version);
Rich Lanea06d0c32013-03-25 08:52:03 -07001852""" % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001853 out.write("""extern void %(cls)s_init(
1854 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
1855""" % dict(cls=cls))
1856
1857 out.write("""
1858/****************************************************************
1859 *
1860 * Delete operator static inline definitions.
1861 * These are here for type checking purposes only
1862 *
1863 ****************************************************************/
1864""")
1865 for cls in of_g.standard_class_order:
1866# if cls in type_maps.inheritance_map:
1867# continue
1868 out.write("""
1869/**
1870 * Delete an object of type %(cls)s_t
1871 * @param obj An instance of type %(cls)s_t
1872 *
1873 * \ingroup %(cls)s
1874 */
1875static inline void
1876%(cls)s_delete(%(cls)s_t *obj) {
1877 of_object_delete((of_object_t *)(obj));
1878}
1879""" % dict(cls=cls))
1880
1881 out.write("""
1882typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
1883 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07001884extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07001885""")
1886
1887 out.write("""
1888/****************************************************************
1889 *
1890 * Function pointer initialization functions
1891 * These are part of the "coerce" type casting for objects
1892 *
1893 ****************************************************************/
1894""")
1895
Rich Laneb604e332013-12-15 13:23:51 -08001896def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001897 """
1898 Generate the new operator for all classes
1899
1900 @param out The file to which to write the functions
1901 """
1902
Rich Laneb604e332013-12-15 13:23:51 -08001903 gen_new_fn_body(cls, out)
1904 gen_init_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07001905
Rich Lanea06d0c32013-03-25 08:52:03 -07001906"""
1907Document generation functions
1908
1909The main reason this is here is to generate documentation per
1910accessor that indicates the versions that support the interface.
1911"""
1912
1913
1914def gen_accessor_doc(out, name):
1915 """
1916 Generate documentation for each accessor function that indicates
1917 the versions supporting the accessor.
1918 """
1919
1920 common_top_matter(out, name)
1921
1922 out.write("/* DOCUMENTATION ONLY */\n")
1923
1924 for cls in of_g.standard_class_order:
1925 if cls in type_maps.inheritance_map:
1926 pass # Check this
1927
1928 out.write("""
1929/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001930 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07001931 * accessors available in all versions unless noted otherwise
1932 *
1933""" % dict(cls=cls))
1934 if loxi_utils.class_is_list(cls):
1935 out.write("""\
1936 * @param first Function of type %(cls)s_first_f.
1937 * Setup a TBD class object to the first entry in the list
1938 * @param next Function of type %(cls)s_next_f.
1939 * Advance a TBD class object to the next entry in the list
1940 * @param append_bind Function of type %(cls)s_append_bind_f
1941 * Setup a TBD class object for append to the end of the current list
1942 * @param append Function of type @ref %(cls)s_append_f.
1943 * Copy an item to the end of a list
1944""" % dict(cls=cls))
1945
1946 for m_name in of_g.ordered_members[cls]:
1947 if m_name in of_g.skip_members:
1948 continue
1949 ver_type_map = field_ver_get(cls, m_name)
1950 (m_type, get_rv) = get_acc_rv(cls, m_name)
1951 if len(ver_type_map) == 3:
1952 # ver_string = "Available in all versions"
1953 ver_string = ""
1954 else:
1955 ver_string = "("
1956 for ver in sorted(ver_type_map):
1957 ver_string += " " + of_g.short_version_names[ver]
1958 ver_string += ")."
1959
1960 f_name = acc_name(cls, m_name)
1961 out.write("""\
1962 * @param %(m_name)s_get/set %(ver_string)s
1963 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
1964 * are of type %(f_name)s_get_f and _set_f.
1965 *
1966""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
1967
1968 out.write("""\
1969 */
1970typedef struct %(cls)s_s %(cls)s_t;
1971""" % dict(cls=cls))
1972
1973 out.write("#endif /* _LOCI_DOC_H_ */\n")