blob: ba232fd8e21e9f8f805b3e65e8891d3c20073efa [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
429 out.write("\n#endif /* Top header file */\n")
430
431def match_c_gen(out, name):
432 """
433 Generate code for
434 @param out The file handle to write to
435 @param name The name of the file
436 """
437 c_match.match_c_top_matter(out, name)
438 c_match.gen_match_conversions(out)
439 c_match.gen_serialize(out)
440 c_match.gen_deserialize(out)
441
Rich Lanea06d0c32013-03-25 08:52:03 -0700442################################################################
443# Top Matter
444################################################################
445
446def common_top_matter(out, name):
447 loxi_utils.gen_c_copy_license(out)
448 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700449
Rich Lanea06d0c32013-03-25 08:52:03 -0700450/****************************************************************
451 * File: %s
452 *
453 * DO NOT EDIT
454 *
455 * This file is automatically generated
456 *
457 ****************************************************************/
458
459""" % name)
460
461 if name[-2:] == ".h":
462 out.write("""
463#if !defined(%(h)s)
464#define %(h)s
465
466""" % dict(h=h_file_to_define(name)))
467
468def base_h_content(out):
469 """
470 Generate base header file content
471
472 @param out The output file object
473 """
474
475 # @fixme Supported version should be generated based on input to LoxiGen
476
477 out.write("""
478/*
479 * Base OpenFlow definitions. These depend only on standard C headers
480 */
481#include <string.h>
482#include <stdint.h>
483
484/* g++ requires this to pick up PRI, etc.
485 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
486 */
487#if !defined(__STDC_FORMAT_MACROS)
488#define __STDC_FORMAT_MACROS
489#endif
490#include <inttypes.h>
491
492#include <stdlib.h>
493#include <assert.h>
494#include <loci/loci_idents.h>
495
496/**
497 * Macro to enable debugging for LOCI.
498 *
499 * This enables debug output to stdout.
500 */
501#define OF_DEBUG_ENABLE
502
503#if defined(OF_DEBUG_ENABLE)
504#include <stdio.h> /* Currently for debugging */
505#define FIXME(str) do { \\
506 fprintf(stderr, "%s\\n", str); \\
507 exit(1); \\
508 } while (0)
509#define debug printf
510#else
511#define FIXME(str)
512#define debug(str, ...)
513#endif /* OF_DEBUG_ENABLE */
514
515/**
516 * The type of a function used by the LOCI dump/show functions to
517 * output text. Essentially the same signature as fprintf. May
518 * be called many times per invocation of e.g. of_object_show().
519 */
520typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
521
522/**
523 * Check if a version is supported
524 */
525#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
526
527""")
528 gen_version_enum(out)
529 out.write("\n")
530
531 # for c_name in of_g.ofp_constants:
532 # val = str(of_g.ofp_constants[c_name])
533 # out.write("#define %s %s\n" % (c_name, val))
534 # out.write("\n")
535
536 out.write("""
537typedef enum of_error_codes_e {
538 OF_ERROR_NONE = 0,
539 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
540 OF_ERROR_PARAM = -2, /* Bad parameter */
541 OF_ERROR_VERSION = -3, /* Version not supported */
542 OF_ERROR_RANGE = -4, /* End of list indication */
543 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
544 OF_ERROR_PARSE = -6, /* Error in parsing data */
545 OF_ERROR_INIT = -7, /* Uninitialized data */
546 OF_ERROR_UNKNOWN = -8 /* Unknown error */
547} of_error_codes_t;
548
549#define OF_ERROR_STRINGS "none", \\
550 "resource", \\
551 "parameter", \\
552 "version", \\
553 "range", \\
554 "incompatible", \\
555 "parse", \\
556 "init", \\
557 "unknown"
558
Rich Laneb157b0f2013-03-27 13:55:28 -0700559extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700560
Rich Lanea8b54632014-02-19 11:17:47 -0800561#ifdef __GNUC__
562#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
563#else
564#define LOCI_NORETURN_ATTR
565#endif
566
567extern void loci_assert_fail(
568 const char *cond,
569 const char *file,
570 unsigned int line) LOCI_NORETURN_ATTR;
571
Rich Lane53757732013-02-23 17:00:10 -0800572#ifndef NDEBUG
Rich Lanea8b54632014-02-19 11:17:47 -0800573#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
Rich Lane53757732013-02-23 17:00:10 -0800574#else
Rich Lanee57f0432014-02-19 10:31:53 -0800575#define LOCI_ASSERT(val)
Rich Lane53757732013-02-23 17:00:10 -0800576#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700577
578/*
579 * Some LOCI object accessors can fail, and it's easy to forget to check.
580 * On certain compilers we can trigger a warning if the error code
581 * is ignored.
582 */
583#ifndef DISABLE_WARN_UNUSED_RESULT
584#ifdef __GNUC__
585#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
586#else
587#define WARN_UNUSED_RESULT
588#endif
589#else
590#define WARN_UNUSED_RESULT
591#endif
592
593typedef union of_generic_u of_generic_t;
594typedef struct of_object_s of_object_t;
595
596/* Define ipv4 address as uint32 */
597typedef uint32_t of_ipv4_t;
598
599/* Table ID is the OF standard uint8 */
600typedef uint8_t of_table_id_t;
601
602#define OF_MAC_ADDR_BYTES 6
603typedef struct of_mac_addr_s {
604 uint8_t addr[OF_MAC_ADDR_BYTES];
605} of_mac_addr_t;
606
607#define OF_IPV6_BYTES 16
608typedef struct of_ipv6_s {
609 uint8_t addr[OF_IPV6_BYTES];
610} of_ipv6_t;
611
612extern const of_mac_addr_t of_mac_addr_all_ones;
613extern const of_mac_addr_t of_mac_addr_all_zeros;
614
615extern const of_ipv6_t of_ipv6_all_ones;
616extern const of_ipv6_t of_ipv6_all_zeros;
617
618/**
619 * Generic zero and all-ones values of size 16 bytes.
620 *
621 * IPv6 is longest data type we worry about for comparisons
622 */
623#define of_all_zero_value of_ipv6_all_zeros
624#define of_all_ones_value of_ipv6_all_ones
625
626/**
627 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
628 */
629#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
630 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
631#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
632 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
633
634/* The octets object is a struct holding pointer and length */
635typedef struct of_octets_s {
636 uint8_t *data;
637 int bytes;
638} of_octets_t;
639
640/* Macro to convert an octet object to a pointer; currently trivial */
641#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
642#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
643#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
644#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
645
646/* Currently these are categorized as scalars */
647typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
648typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
649typedef char of_desc_str_t[OF_DESC_STR_LEN];
650typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
Rich Lanef8a3d002014-03-19 13:33:52 -0700651typedef char of_str64_t[64];
Rich Lanea06d0c32013-03-25 08:52:03 -0700652
Rich Lane3b2fd832013-09-24 13:44:08 -0700653typedef struct of_bitmap_128_s {
654 uint64_t hi;
655 uint64_t lo;
656} of_bitmap_128_t;
657
Rich Lanefab0c822013-12-30 11:46:48 -0800658typedef struct of_checksum_128_s {
659 uint64_t hi;
660 uint64_t lo;
661} of_checksum_128_t;
662
Rich Lanea06d0c32013-03-25 08:52:03 -0700663/* These are types which change across versions. */
664typedef uint32_t of_port_no_t;
665typedef uint16_t of_fm_cmd_t;
666typedef uint64_t of_wc_bmap_t;
667typedef uint64_t of_match_bmap_t;
668
669#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
670#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
671#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
672#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
673#define MALLOC(bytes) malloc(bytes)
674#define FREE(ptr) free(ptr)
675
676/** Try an operation and return on failure. */
677#define OF_TRY(op) do { \\
678 int _rv; \\
679 if ((_rv = (op)) < 0) { \\
680 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
681 return _rv; \\
682 } \\
683 } while (0)
684
685/* The extent of an OF match object is determined by its length field, but
686 * aligned to 8 bytes
687 */
688
689#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
690
Rich Lanedfcafae2014-03-06 16:56:49 -0800691#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
Rich Lanea06d0c32013-03-25 08:52:03 -0700692#define U16_NTOH(val) (val)
693#define U32_NTOH(val) (val)
694#define U64_NTOH(val) (val)
695#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
696#define U16_HTON(val) (val)
697#define U32_HTON(val) (val)
698#define U64_HTON(val) (val)
699#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
700#else /* Little Endian */
Rich Lane69e247e2014-03-05 10:27:22 -0800701#define U16_NTOH(val) (((val) >> 8) | (((val) & 0xff) << 8))
Rich Lanea06d0c32013-03-25 08:52:03 -0700702#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
703 (((val) & 0x00ff0000) >> 8) | \\
704 (((val) & 0x0000ff00) << 8) | \\
705 (((val) & 0x000000ff) << 24))
706#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
707 (((val) & 0x00ff000000000000LL) >> 40) | \\
708 (((val) & 0x0000ff0000000000LL) >> 24) | \\
709 (((val) & 0x000000ff00000000LL) >> 8) | \\
710 (((val) & 0x00000000ff000000LL) << 8) | \\
711 (((val) & 0x0000000000ff0000LL) << 24) | \\
712 (((val) & 0x000000000000ff00LL) << 40) | \\
713 (((val) & 0x00000000000000ffLL) << 56))
714#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
715#define U16_HTON(val) U16_NTOH(val)
716#define U32_HTON(val) U32_NTOH(val)
717#define U64_HTON(val) U64_NTOH(val)
718#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
719#endif
720
721/****************************************************************
722 *
723 * The following are internal definitions used by the automatically
724 * generated code. Users should not reference these definitions
725 * as they may change between versions of this code
726 *
727 ****************************************************************/
728
729#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
730 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
731#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
732#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
733 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
734
735#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
736 (FIXED_LEN + of_message_out_actions_len_get(obj))
737
738""")
739
740def external_h_top_matter(out, name):
741 """
742 Generate top matter for external header file
743
744 @param name The name of the output file
745 @param out The output file object
746 """
747 common_top_matter(out, name)
748 out.write("""
749#include <loci/loci_base.h>
750#include <loci/of_message.h>
751#include <loci/of_match.h>
752#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800753#include <loci/loci_classes.h>
Rich Lanedc46fe22014-04-03 15:10:38 -0700754#include <loci/loci_class_metadata.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700755
756/****************************************************************
757 *
758 * This file is divided into the following sections.
759 *
760 * A few object specific macros
761 * Class typedefs (no struct definitions)
762 * Per-data type accessor function typedefs
763 * Per-class new/delete function typedefs
764 * Per-class static delete functions
765 * Per-class, per-member accessor declarations
766 * Per-class structure definitions
767 * Generic union (inheritance) definitions
768 * Pointer set function declarations
769 * Some special case macros
770 *
771 ****************************************************************/
772""")
773
Rich Lanea06d0c32013-03-25 08:52:03 -0700774################################################################
775#
776################################################################
777
778def gen_version_enum(out):
779 """
780 Generate the enumerated type for versions in LoxiGen
781 @param out The file object to which to write the decs
782
783 This just uses the wire versions for now
784 """
785 out.write("""
786/**
787 * Enumeration of OpenFlow versions
788 *
789 * The wire protocol numbers are currently used for values of the corresponding
790 * version identifiers.
791 */
792typedef enum of_version_e {
793 OF_VERSION_UNKNOWN = 0,
794""")
795
796 is_first = True
797 max = 0
798 for v in of_g.wire_ver_map:
799 if is_first:
800 is_first = False
801 else:
802 out.write(",\n")
803 if v > max:
804 max = v
805 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
806
807 out.write("""
808} of_version_t;
809
810/**
811 * @brief Use this when declaring arrays indexed by wire version
812 */
813#define OF_VERSION_ARRAY_MAX %d
814""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700815
Rich Lanea06d0c32013-03-25 08:52:03 -0700816def gen_object_enum(out):
817 """
818 Generate the enumerated type for object identification in LoxiGen
819 @param out The file object to which to write the decs
820 """
821 out.write("""
822
823/**
824 * Enumeration of OpenFlow objects
825 *
826 * We enumerate the OpenFlow objects used internally. Note that some
827 * message types are determined both by an outer type (message type like
828 * stats_request) and an inner type (port stats). These are different
829 * messages in ofC.
830 *
831 * These values are for internal use only. They will change with
832 * different versions of ofC.
833 */
834
835typedef enum of_object_id_e {
836 /* Root object type */
837 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
838 OF_OBJECT = 0, /* Generic, untyped object */
839
840 /* OpenFlow message objects */
841""")
842 last = 0
843 msg_count = 0
844 for cls in of_g.ordered_messages:
845 out.write(" %s = %d,\n" % (enum_name(cls),
846 of_g.unified[cls]["object_id"]))
847 msg_count = of_g.unified[cls]["object_id"] + 1
848
849 out.write("\n /* Non-message objects */\n")
850 for cls in of_g.ordered_non_messages:
851 out.write(" %s = %d,\n" % (enum_name(cls),
852 of_g.unified[cls]["object_id"]))
853 last = of_g.unified[cls]["object_id"]
854 out.write("\n /* List objects */\n")
855 for cls in of_g.ordered_list_objects:
856 out.write(" %s = %d,\n" % (enum_name(cls),
857 of_g.unified[cls]["object_id"]))
858 last = of_g.unified[cls]["object_id"]
859
Rich Lanea06d0c32013-03-25 08:52:03 -0700860 out.write("""
861 OF_OBJECT_COUNT = %d
862} of_object_id_t;
863
Rich Laneb157b0f2013-03-27 13:55:28 -0700864extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700865
866#define OF_MESSAGE_OBJECT_COUNT %d
867""" % ((last + 1), msg_count))
868
869 # Generate object type range checking for inheritance classes
870
871 # @fixme These should be determined algorithmicly
872 out.write("""
873/*
874 * Macros to check if an object ID is within an inheritance class range
875 */
876""")
877 # Alphabetical order for 'last'
878 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
879 of_oxm="OF_OXM_VLAN_VID_MASKED",
880 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
881 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
882 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
883 # @FIXME add meter_band ?
884 )
885 for cls, last in last_ids.items():
886 out.write("""
887#define %(enum)s_FIRST_ID (%(enum)s + 1)
888#define %(enum)s_LAST_ID %(last)s
889#define %(enum)s_VALID_ID(id) \\
890 ((id) >= %(enum)s_FIRST_ID && \\
891 (id) <= %(enum)s_LAST_ID)
892""" % dict(enum=enum_name(cls), last=last))
893 out.write("""
894/**
895 * Function to check a wire ID
896 * @param object_id The ID to check
897 * @param base_object_id The inheritance parent, if applicable
898 * @returns boolean: If base_object_id is an inheritance class, check if
899 * object_id is valid as a subclass. Otherwise return 1.
900 *
901 * Note: Could check that object_id == base_object_id in the
902 * second case.
903 */
904static inline int
905of_wire_id_valid(int object_id, int base_object_id) {
906 switch (base_object_id) {
907 case OF_ACTION:
908 return OF_ACTION_VALID_ID(object_id);
909 case OF_OXM:
910 return OF_OXM_VALID_ID(object_id);
911 case OF_QUEUE_PROP:
912 return OF_QUEUE_PROP_VALID_ID(object_id);
913 case OF_TABLE_FEATURE_PROP:
914 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
915 case OF_INSTRUCTION:
916 return OF_INSTRUCTION_VALID_ID(object_id);
917 default:
918 break;
919 }
920 return 1;
921}
922""")
923
Rich Lanea06d0c32013-03-25 08:52:03 -0700924################################################################
925#
926# Internal Utility Functions
927#
928################################################################
929
930
931def acc_name(cls, m_name):
932 """
933 Generate the root name of an accessor function for typedef
934 @param cls The class name
935 @param m_name The member name
936 """
937 (m_type, get_rv) = get_acc_rv(cls, m_name)
938 return "%s_%s" % (cls, m_type)
939
940def get_acc_rv(cls, m_name):
941 """
942 Determine the data type and return type for a get accessor.
943
944 The return type may be "void" or it may be the accessor type
945 depending on the system configuration and on the data type.
946
947 @param cls The class name
948 @param m_name The member name
949 @return A pair (m_type, rv) where m_type is the unified type of the
950 member and rv is the get_accessor return type
951 """
952 member = of_g.unified[cls]["union"][m_name]
953 m_type = member["m_type"]
954 rv = "int"
Rich Lanea06d0c32013-03-25 08:52:03 -0700955 if m_type[-2:] == "_t":
956 m_type = m_type[:-2]
957
958 return (m_type, rv)
959
960def param_list(cls, m_name, a_type):
961 """
962 Generate the parameter list (no parens) for an a_type accessor
963 @param cls The class name
964 @param m_name The member name
965 @param a_type One of "set" or "get" or TBD
966 """
967 member = of_g.unified[cls]["union"][m_name]
968 m_type = member["m_type"]
969 params = ["%s_t *obj" % cls]
970 if a_type == "set":
971 if loxi_utils.type_is_scalar(m_type):
972 params.append("%s %s" % (m_type, m_name))
973 else:
974 params.append("%s *%s" % (m_type, m_name))
975 elif a_type in ["get", "bind"]:
976 params.append("%s *%s" % (m_type, m_name))
977 else:
978 debug("Class %s, name %s Bad param list a_type: %s" %
979 (cls, m_name, a_type))
980 sys.exit(1)
981 return params
982
Rich Lanea06d0c32013-03-25 08:52:03 -0700983def field_ver_get(cls, m_name):
984 """
985 Generate a dict, indexed by wire version, giving a pair (type, offset)
986
987 @param cls The class name
988 @param m_name The name of the class member
989
990 If offset is not known for m_name, the type
991 A dict is used for more convenient indexing.
992 """
993 result = {}
994
995 for ver in of_g.unified[cls]:
996 if type(ver) == type(0): # It's a version
997 if "use_version" in of_g.unified[cls][ver]: # deref version ref
998 ref_ver = of_g.unified[cls][ver]["use_version"]
999 members = of_g.unified[cls][ref_ver]["members"]
1000 else:
1001 members = of_g.unified[cls][ver]["members"]
1002 idx = loxi_utils.member_to_index(m_name, members)
1003 if (idx < 0):
1004 continue # Member not in this version
1005 m_type = members[idx]["m_type"]
1006 offset = members[idx]["offset"]
1007
1008 # If m_type is mixed, get wire version type from global data
1009 if m_type in of_g.of_mixed_types and \
1010 ver in of_g.of_mixed_types[m_type]:
1011 m_type = of_g.of_mixed_types[m_type][ver]
1012
1013 # add version to result list
1014 result[ver] = (m_type, offset)
1015
1016 return result
1017
1018def v3_match_offset_get(cls):
1019 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001020 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001021 otherwise return -1
1022 """
1023 result = field_ver_get(cls, "match")
1024 if of_g.VERSION_1_2 in result:
1025 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1026 return result[of_g.VERSION_1_2][1]
1027 return -1
1028
1029################################################################
1030#
1031# OpenFlow Object Definitions
1032#
1033################################################################
1034
Rich Lanea06d0c32013-03-25 08:52:03 -07001035def gen_generics(out):
1036 for (cls, subclasses) in type_maps.inheritance_map.items():
1037 out.write("""
1038/**
1039 * Inheritance super class for %(cls)s
1040 *
1041 * This class is the union of %(cls)s classes. You can refer
1042 * to it untyped by refering to the member 'header' whose structure
1043 * is common across all sub-classes.
1044 */
1045
1046union %(cls)s_u {
1047 %(cls)s_header_t header; /* Generic instance */
1048""" % dict(cls=cls))
1049 for subcls in sorted(subclasses):
1050 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1051 out.write("};\n")
1052
1053def gen_struct_typedefs(out):
1054 """
1055 Generate typedefs for all struct objects
1056 @param out The file for output, already open
1057 """
1058
1059 out.write("\n/* LOCI inheritance parent typedefs */\n")
1060 for cls in type_maps.inheritance_map:
1061 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1062 out.write("\n/* LOCI object typedefs */\n")
1063 for cls in of_g.standard_class_order:
1064 if cls in type_maps.inheritance_map:
1065 continue
Rich Lane85767872013-12-15 16:24:42 -08001066 template = "typedef of_object_t %(cls)s_t;\n"
1067 out.write(template % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001068
1069 out.write("""
1070/****************************************************************
1071 *
1072 * Additional of_object defines
1073 * These are needed for some static inline ops, so we put them here.
1074 *
1075 ****************************************************************/
1076
1077/* Delete an OpenFlow object without reference to its type */
1078extern void of_object_delete(of_object_t *obj);
1079
1080""")
1081
Rich Lanea06d0c32013-03-25 08:52:03 -07001082################################################################
1083#
1084# List accessor code generation
1085#
1086# Currently these all implement copy on read semantics
1087#
1088################################################################
1089
1090def init_call(e_type, obj, ver, length, cw):
1091 """
1092 Generate the init call given the strings for params
1093 """
1094 hdr = "" # If inheritance type, coerce to hdr object
1095 obj_name = obj
1096 if e_type in type_maps.inheritance_map:
1097 hdr = "_header"
1098 obj_name = "(%s_header_t *)" % e_type + obj
1099
1100 return """\
1101%(e_type)s%(hdr)s_init(%(obj_name)s,
1102 %(ver)s, %(length)s, %(cw)s)\
1103""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1104 length=length, cw=cw)
1105
1106def gen_list_first(out, cls, e_type):
1107 """
1108 Generate the body of a list_first operation
1109 @param cls The class name for which code is being generated
1110 @param e_type The element type of the list
1111 @param out The file to which to write
1112 """
1113 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1114 if e_type in type_maps.inheritance_map:
1115 len_str = "obj->header.length"
1116 else:
1117 len_str = "obj->length"
1118
1119 out.write("""
1120/**
1121 * Associate an iterator with a list
1122 * @param list The list to iterate over
1123 * @param obj The list entry iteration pointer
1124 * @return OF_ERROR_RANGE if the list is empty (end of list)
1125 *
1126 * The obj instance is completely initialized. The caller is responsible
1127 * for cleaning up any wire buffers associated with obj before this call
1128 */
1129
1130int
1131%(cls)s_first(%(cls)s_t *list,
1132 %(e_type)s_t *obj)
1133{
1134 int rv;
1135
1136 %(i_call)s;
1137 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1138 return rv;
1139 }
1140""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1141
1142 # Special case flow_stats_entry lists
1143
1144 out.write("""
1145 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1146 list->length);
1147 if (%(len_str)s == 0) {
1148 return OF_ERROR_PARSE;
1149 }
1150
1151 return rv;
1152}
1153""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1154
Rich Lanea06d0c32013-03-25 08:52:03 -07001155def gen_list_next(out, cls, e_type):
1156 """
1157 Generate the body of a list_next operation
1158 @param cls The class name for which code is being generated
1159 @param e_type The element type of the list
1160 @param out The file to which to write
1161 """
1162
1163 if e_type in type_maps.inheritance_map:
1164 len_str = "obj->header.length"
1165 else:
1166 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001167
Rich Lanea06d0c32013-03-25 08:52:03 -07001168 out.write("""
1169/**
1170 * Advance an iterator to the next element in a list
1171 * @param list The list being iterated
1172 * @param obj The list entry iteration pointer
1173 * @return OF_ERROR_RANGE if already at the last entry on the list
1174 *
1175 */
1176
1177int
1178%(cls)s_next(%(cls)s_t *list,
1179 %(e_type)s_t *obj)
1180{
1181 int rv;
1182
1183 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1184 return rv;
1185 }
1186
1187 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1188 list->length);
1189
1190 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1191 return OF_ERROR_PARSE;
1192 }
1193
1194 return rv;
1195}
1196""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1197
1198def gen_list_append(out, cls, e_type):
1199 """
1200 Generate the body of a list append functions
1201 @param cls The class name for which code is being generated
1202 @param e_type The element type of the list
1203 @param out The file to which to write
1204 """
1205
1206 out.write("""
1207/**
1208 * Set up to append an object of type %(e_type)s to an %(cls)s.
1209 * @param list The list that is prepared for append
1210 * @param obj Pointer to object to hold data to append
1211 *
1212 * The obj instance is completely initialized. The caller is responsible
1213 * for cleaning up any wire buffers associated with obj before this call.
1214 *
1215 * See the generic documentation for of_list_append_bind.
1216 */
1217
1218int
1219%(cls)s_append_bind(%(cls)s_t *list,
1220 %(e_type)s_t *obj)
1221{
1222 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1223}
1224
1225/**
1226 * Append an item to a %(cls)s list.
1227 *
1228 * This copies data from item and leaves item untouched.
1229 *
1230 * See the generic documentation for of_list_append.
1231 */
1232
1233int
1234%(cls)s_append(%(cls)s_t *list,
1235 %(e_type)s_t *item)
1236{
1237 return of_list_append((of_object_t *)list, (of_object_t *)item);
1238}
1239
1240""" % dict(cls=cls, e_type=e_type))
1241
1242def gen_list_accessors(out, cls):
1243 e_type = loxi_utils.list_to_entry_type(cls)
1244 gen_list_first(out, cls, e_type)
1245 gen_list_next(out, cls, e_type)
1246 gen_list_append(out, cls, e_type)
1247
1248################################################################
1249#
1250# Accessor Functions
1251#
1252################################################################
1253
Andreas Wundsam53256162013-05-02 14:05:53 -07001254
Rich Lanea06d0c32013-03-25 08:52:03 -07001255def gen_accessor_declarations(out):
1256 """
1257 Generate the declaration of each version independent accessor
1258
1259 @param out The file to which to write the decs
1260 """
1261
1262 out.write("""
1263/****************************************************************
1264 *
1265 * Unified, per-member accessor function declarations
1266 *
1267 ****************************************************************/
1268""")
1269 for cls in of_g.standard_class_order:
1270 if cls in type_maps.inheritance_map:
1271 continue
1272 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1273 for m_name in of_g.ordered_members[cls]:
1274 if m_name in of_g.skip_members:
1275 continue
1276 m_type = loxi_utils.member_base_type(cls, m_name)
1277 base_name = "%s_%s" % (cls, m_name)
1278 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1279 get_ret_type = accessor_return_type("get", m_type)
1280 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1281 set_ret_type = accessor_return_type("set", m_type)
1282 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1283 bind_ret_type = accessor_return_type("bind", m_type)
1284
1285 if loxi_utils.type_is_of_object(m_type):
1286 # Generate bind accessors, but not get accessor
1287 out.write("""
1288extern %(set_ret_type)s %(base_name)s_set(
1289 %(sparams)s);
1290extern %(bind_ret_type)s %(base_name)s_bind(
1291 %(bparams)s);
1292extern %(m_type)s *%(cls)s_%(m_name)s_get(
1293 %(cls)s_t *obj);
1294""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1295 m_name=m_name, m_type=m_type, cls=cls,
1296 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1297 else:
1298 out.write("""
1299extern %(set_ret_type)s %(base_name)s_set(
1300 %(sparams)s);
1301extern %(get_ret_type)s %(base_name)s_get(
1302 %(gparams)s);
1303""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1304 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001305
Rich Lanea06d0c32013-03-25 08:52:03 -07001306 if loxi_utils.class_is_list(cls):
1307 e_type = loxi_utils.list_to_entry_type(cls)
1308 out.write("""
1309extern int %(cls)s_first(
1310 %(cls)s_t *list, %(e_type)s_t *obj);
1311extern int %(cls)s_next(
1312 %(cls)s_t *list, %(e_type)s_t *obj);
1313extern int %(cls)s_append_bind(
1314 %(cls)s_t *list, %(e_type)s_t *obj);
1315extern int %(cls)s_append(
1316 %(cls)s_t *list, %(e_type)s_t *obj);
1317
1318/**
1319 * Iteration macro for list of type %(cls)s
1320 * @param list Pointer to the list being iterated over of
1321 * type %(cls)s
1322 * @param elt Pointer to an element of type %(e_type)s
1323 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1324 */
1325#define %(u_cls)s_ITER(list, elt, rv) \\
1326 for ((rv) = %(cls)s_first((list), (elt)); \\
1327 (rv) == OF_ERROR_NONE; \\
1328 (rv) = %(cls)s_next((list), (elt)))
1329""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1330
1331
1332def wire_accessor(m_type, a_type):
1333 """
1334 Returns the name of the a_type accessor for low level wire buff offset
1335 @param m_type The member type
1336 @param a_type The accessor type (set or get)
1337 """
1338 # Strip off _t if present
1339 if m_type in of_g.of_base_types:
1340 m_type = of_g.of_base_types[m_type]["short_name"]
1341 if m_type in of_g.of_mixed_types:
1342 m_type = of_g.of_mixed_types[m_type]["short_name"]
1343 if m_type[-2:] == "_t":
1344 m_type = m_type[:-2]
1345 if m_type == "octets":
1346 m_type = "octets_data"
1347 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1348
Rich Lane713d9282013-12-30 15:21:35 -08001349def get_len_macro(cls, m_name, m_type, version):
Rich Lanea06d0c32013-03-25 08:52:03 -07001350 """
1351 Get the length macro for m_type in cls
1352 """
1353 if m_type.find("of_match") == 0:
1354 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1355 if m_type.find("of_list_oxm") == 0:
1356 return "wire_match_len(obj, 0) - 4"
1357 if loxi_utils.class_is_tlv16(m_type):
1358 return "_TLV16_LEN(obj, offset)"
1359 if cls == "of_packet_out" and m_type == "of_list_action_t":
1360 return "_PACKET_OUT_ACTION_LEN(obj)"
Rich Lane713d9282013-12-30 15:21:35 -08001361 if cls == "of_bsn_gentable_entry_add" and m_name == "key":
1362 return "of_object_u16_get(obj, 18)"
1363 if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
1364 return "of_object_u16_get(obj, 2)"
1365 if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
1366 return "of_object_u16_get(obj, 2)"
Rich Lanea06d0c32013-03-25 08:52:03 -07001367 # Default is everything to the end of the object
1368 return "_END_LEN(obj, offset)"
1369
1370def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1371 """
1372 Generate the sub-object offset and length calculations for accessors
1373 @param out File being written
1374 @param m_name Name of member
1375 @param version Wire version being processed
1376 @param a_type The accessor type (set or get)
1377 @param m_type The original member type
1378 @param offset The offset of the object or -1 if not fixed
1379 """
1380 # determine offset
1381 o_str = "%d" % offset # Default is fixed length
1382 if offset == -1:
1383 # There are currently 4 special cases for this
1384 # In general, get offset and length of predecessor
1385 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1386 pass
1387 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1388 pass
1389 elif (cls == "of_packet_in" and m_name == "data"):
1390 pass
1391 elif (cls == "of_packet_out" and m_name == "data"):
1392 pass
Rich Lane713d9282013-12-30 15:21:35 -08001393 elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
1394 pass
1395 elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
1396 pass
1397 elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
1398 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001399 else:
1400 debug("Error: Unknown member with offset == -1")
1401 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1402 sys.exit(1)
1403 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1404
1405 out.write("""\
1406 offset = %s;
1407""" % o_str);
1408
1409 # This could be moved to main body but for version check
1410 if not loxi_utils.type_is_scalar(m_type):
1411 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1412 m_type == "of_match_t":
Rich Lane713d9282013-12-30 15:21:35 -08001413 len_macro = get_len_macro(cls, m_name, m_type, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001414 else:
1415 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1416 out.write(" cur_len = %s;\n" % len_macro)
1417 out.write(" break;\n")
1418
1419def length_of(m_type, version):
1420 """
1421 Return the length of a type based on the version
1422 """
1423 if m_type in of_g.of_mixed_types:
1424 m_type = of_g.of_mixed_types[m_type][version]
1425 if m_type in of_g.of_base_types:
1426 return of_g.of_base_types[m_type]["bytes"]
1427 if (m_type[:-2], version) in of_g.base_length:
1428 return of_g.base_length[(m_type[:-2], version)]
1429 print "Unknown length request", m_type, version
1430 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001431
Rich Lanea06d0c32013-03-25 08:52:03 -07001432
1433def gen_get_accessor_body(out, cls, m_type, m_name):
1434 """
1435 Generate the common operations for a get accessor
1436 """
1437 if loxi_utils.type_is_scalar(m_type):
1438 ver = "" # See if version required for scalar update
1439 if m_type in of_g.of_mixed_types:
1440 ver = "ver, "
1441 out.write("""\
1442 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1443""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1444
1445 if m_type == "of_port_no_t":
1446 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1447 elif m_type == "of_octets_t":
1448 out.write("""\
Rich Lanee57f0432014-02-19 10:31:53 -08001449 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001450 %(m_name)s->bytes = cur_len;
1451 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1452""" % dict(m_name=m_name))
1453 elif m_type == "of_match_t":
1454 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001455 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001456 match_octets.bytes = cur_len;
1457 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
1458 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
1459""" % dict(m_name=m_name))
Rich Lane90020b42014-04-07 12:05:45 -07001460 elif m_type == "of_oxm_header_t":
1461 out.write("""
1462 /* Initialize child */
1463 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1464 /* Attach to parent */
1465 %(m_name)s->parent = (of_object_t *)obj;
1466 %(m_name)s->wbuf = obj->wbuf;
1467 %(m_name)s->obj_offset = abs_offset;
1468 %(m_name)s->length = cur_len;
1469 of_object_wire_init(%(m_name)s, OF_OXM, 0);
1470""" % dict(m_type=m_type[:-2], m_name=m_name))
Wilson Ngd6181882014-04-14 16:28:35 -07001471 elif m_type == "of_bsn_vport_header_t":
1472 out.write("""
1473 /* Initialize child */
1474 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1475 /* Attach to parent */
1476 %(m_name)s->parent = (of_object_t *)obj;
1477 %(m_name)s->wbuf = obj->wbuf;
1478 %(m_name)s->obj_offset = abs_offset;
1479 %(m_name)s->length = cur_len;
1480 of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
1481""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001482 else:
1483 out.write("""
1484 /* Initialize child */
1485 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1486 /* Attach to parent */
1487 %(m_name)s->parent = (of_object_t *)obj;
Rich Lanecdd542d2014-04-03 16:13:12 -07001488 %(m_name)s->wbuf = obj->wbuf;
1489 %(m_name)s->obj_offset = abs_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -07001490 %(m_name)s->length = cur_len;
1491""" % dict(m_type=m_type[:-2], m_name=m_name))
1492
1493
1494def gen_set_accessor_body(out, cls, m_type, m_name):
1495 """
1496 Generate the contents of a set accessor
1497 """
1498 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1499 ver = "" # See if version required for scalar update
1500 if m_type in of_g.of_mixed_types:
1501 ver = "ver, "
1502 cur_len = "" # See if version required for scalar update
1503 if m_type == "of_octets_t":
1504 cur_len = ", cur_len"
1505 out.write("""\
1506 new_len = %(m_name)s->bytes;
1507 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1508""" % dict(m_name=m_name))
1509 out.write("""\
1510 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1511""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1512 m_name=m_name))
1513
1514 elif m_type == "of_match_t":
1515 out.write("""
1516 /* Match object */
1517 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1518 new_len = match_octets.bytes;
1519 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1520 match_octets.data, new_len);
1521 /* Free match serialized octets */
1522 FREE(match_octets.data);
1523""" % dict(m_name=m_name))
1524
1525 else: # Other object type
1526 out.write("\n /* LOCI object type */")
1527 # Need to special case OXM list
1528 out.write("""
1529 new_len = %(m_name)s->length;
1530 /* If underlying buffer already shared; nothing to do */
Rich Lanecdd542d2014-04-03 16:13:12 -07001531 if (obj->wbuf == %(m_name)s->wbuf) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001532 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1533 /* Verify that the offsets are correct */
Rich Lanee57f0432014-02-19 10:31:53 -08001534 LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1535 /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
Rich Lanea06d0c32013-03-25 08:52:03 -07001536 return %(ret_success)s;
1537 }
1538
1539 /* Otherwise, replace existing object in data buffer */
1540 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1541 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1542""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1543
1544 if not loxi_utils.type_is_scalar(m_type):
1545 if cls == "of_packet_out" and m_type == "of_list_action_t":
1546 out.write("""
1547 /* Special case for setting action lengths */
1548 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1549""" % dict(m_name=m_name))
Rich Lane713d9282013-12-30 15:21:35 -08001550 elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
1551 out.write("""
1552 /* Special case for setting key length */
1553 of_object_u16_set(obj, 18, %(m_name)s->length);
1554""" % dict(m_name=m_name))
1555 elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
1556 out.write("""
1557 /* Special case for setting key length */
1558 of_object_u16_set(obj, 2, %(m_name)s->length);
1559""" % dict(m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001560 elif m_type not in ["of_match_t", "of_octets_t"]:
1561 out.write("""
1562 /* @fixme Shouldn't this precede copying value's data to buffer? */
Rich Lanedc46fe22014-04-03 15:10:38 -07001563 of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001564""" % dict(m_name=m_name))
1565 out.write("""
1566 /* Not scalar, update lengths if needed */
1567 delta = new_len - cur_len;
1568 if (delta != 0) {
1569 /* Update parent(s) */
1570 of_object_parent_length_update((of_object_t *)obj, delta);
1571 }
1572""")
1573
1574def obj_assert_check(cls):
1575 """
1576 The body of the assert check for an accessor
1577 We allow all versions of add/delete/modify to use the same accessors
1578 """
1579 if cls in ["of_flow_modify", "of_flow_modify_strict",
1580 "of_flow_delete", "of_flow_delete_strict",
1581 "of_flow_add"]:
1582 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1583 else:
1584 return "obj->object_id == %s" % cls.upper()
1585
1586def gen_of_object_get(out, cls, m_name, m_type):
1587 sub_cls = m_type[:-2]
1588 out.write("""
1589/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001590 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001591 * a %(cls)s instance.
1592 *
1593 * @param obj Pointer to the source of type %(cls)s_t
1594 * @returns A pointer to a new instance of type %(m_type)s whose contents
1595 * match that of %(m_name)s from source
1596 * @returns NULL if an error occurs
1597 */
1598%(m_type)s *
1599%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1600 %(m_type)s _%(m_name)s;
1601 %(m_type)s *_%(m_name)s_ptr;
1602
1603 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1604 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1605 return _%(m_name)s_ptr;
1606}
1607""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1608
1609def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1610 """
1611 Generate the body of a set or get accessor function
1612
1613 @param out The file to which to write the decs
1614 @param cls The class name
1615 @param m_name The member name
1616 @param ver_type_map Maps (type, offset) pairs to a list of versions
1617 @param a_type The accessor type, set or get
1618 @param m_type The original member type
1619
1620 The type values in ver_type_map are now ignored as we've pushed down
1621 the type munging to the lower level.
1622
1623 This is unified because the version switch case processing is the
1624 same for both set and get
1625 """
1626 out.write("""{
1627 of_wire_buffer_t *wbuf;
1628 int offset = 0; /* Offset of value relative to the start obj */
1629 int abs_offset; /* Offset of value relative to start of wbuf */
1630 of_version_t ver;
1631""")
1632
1633 if not loxi_utils.type_is_scalar(m_type):
1634 out.write("""\
1635 int cur_len = 0; /* Current length of object data */
1636""")
1637 if a_type == "set":
1638 out.write("""\
1639 int new_len, delta; /* For set, need new length and delta */
1640""")
1641
1642 # For match, need octet string for set/get
1643 if m_type == "of_match_t":
1644 out.write("""\
1645 of_octets_t match_octets; /* Serialized string for match */
1646""")
1647
1648 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001649 LOCI_ASSERT(%(assert_str)s);
Rich Lanea06d0c32013-03-25 08:52:03 -07001650 ver = obj->version;
1651 wbuf = OF_OBJECT_TO_WBUF(obj);
Rich Lanee57f0432014-02-19 10:31:53 -08001652 LOCI_ASSERT(wbuf != NULL);
Rich Lanea06d0c32013-03-25 08:52:03 -07001653
1654 /* By version, determine offset and current length (where needed) */
1655 switch (ver) {
1656""" % dict(assert_str=obj_assert_check(cls)))
1657
1658 for first in sorted(ver_type_map):
1659 (prev_t, prev_o) = ver_type_map[first]
1660 prev_len = length_of(prev_t, first)
1661 prev = first
1662 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1663 break
1664
1665 for next in sorted(ver_type_map):
1666 if next == first:
1667 continue
1668
1669 (t, o) = ver_type_map[next]
1670 cur_len = length_of(t, next)
1671 if o == prev_o and cur_len == prev_len:
1672 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1673 continue
1674 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1675 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1676 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1677
1678 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1679 out.write("""\
1680 default:
Rich Lanee57f0432014-02-19 10:31:53 -08001681 LOCI_ASSERT(0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001682 }
1683
1684 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
Rich Lanee57f0432014-02-19 10:31:53 -08001685 LOCI_ASSERT(abs_offset >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001686""")
1687 if not loxi_utils.type_is_scalar(m_type):
Rich Lanee57f0432014-02-19 10:31:53 -08001688 out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001689
1690 # Now generate the common accessor code
1691 if a_type in ["get", "bind"]:
1692 gen_get_accessor_body(out, cls, m_type, m_name)
1693 else:
1694 gen_set_accessor_body(out, cls, m_type, m_name)
1695
1696 out.write("""
1697 OF_LENGTH_CHECK_ASSERT(obj);
1698
1699 return %s;
1700}
1701""" % accessor_return_success(a_type, m_type))
1702
1703def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1704 """
1705 For generating the bind call for OF sub-objects
1706 """
1707
1708 params = ",\n ".join(param_list(cls, m_name, "bind"))
1709 out.write("""
1710/**
1711 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1712 * member %(m_name)s
1713 * @param obj Pointer to an object of type %(cls)s.
1714 * @param %(m_name)s Pointer to the child object of type
1715 * %(m_type)s to be filled out.
1716 * \ingroup %(cls)s
1717 *
1718 * The parameter %(m_name)s is filled out to point to the same underlying
1719 * wire buffer as its parent.
1720 *
1721 */
1722""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1723
1724 ret_type = accessor_return_type("bind", m_type)
1725 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1726 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1727
1728def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
1729 """
1730 For generating the get call for non- OF sub-objects
1731 """
1732 params = ",\n ".join(param_list(cls, m_name, "get"))
1733 out.write("""
1734/**
1735 * Get %(m_name)s from an object of type %(cls)s.
1736 * @param obj Pointer to an object of type %(cls)s.
1737 * @param %(m_name)s Pointer to the child object of type
1738 * %(m_type)s to be filled out.
1739 *
1740 */
1741""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1742
1743 ret_type = accessor_return_type("get", m_type)
1744 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
1745 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
1746
Rich Lanece2e4642013-12-15 12:05:45 -08001747def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001748 for m_name in of_g.ordered_members[cls]:
1749 if m_name in of_g.skip_members:
1750 continue
1751 m_type = loxi_utils.member_base_type(cls, m_name)
1752 ver_type_map = field_ver_get(cls, m_name)
1753
1754 # Generate get/bind pending on member type
1755 # FIXME: Does this do the right thing for match?
1756 if loxi_utils.type_is_of_object(m_type):
1757 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
1758 gen_of_object_get(out, cls, m_name, m_type)
1759 else:
1760 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
1761
1762 # Now generate set accessor for all objects
1763 params = ",\n ".join(param_list(cls, m_name, "set"))
1764 out.write("""
1765/**
1766 * Set %(m_name)s in an object of type %(cls)s.
1767 * @param obj Pointer to an object of type %(cls)s.
1768""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1769 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1770 out.write("""\
1771 * @param %(m_name)s The value to write into the object
1772 */
1773""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1774 else:
1775 out.write("""\
1776 * @param %(m_name)s Pointer to the child of type %(m_type)s.
1777 *
1778 * If the child's wire buffer is the same as the parent's, then
1779 * nothing is done as the changes have already been registered in the
1780 * parent. Otherwise, the data in the child's wire buffer is inserted
1781 * into the parent's and the appropriate lengths are updated.
1782 */
1783""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1784 ret_type = accessor_return_type("set", m_type)
1785 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
1786 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
1787
Rich Lanea06d0c32013-03-25 08:52:03 -07001788################################################################
1789#
1790# New/Delete Function Definitions
1791#
1792################################################################
1793
Rich Lanea06d0c32013-03-25 08:52:03 -07001794################################################################
1795# Routines to generate the body of new/delete functions
1796################################################################
1797
1798def gen_init_fn_body(cls, out):
1799 """
1800 Generate function body for init function
1801 @param cls The class name for the function
1802 @param out The file to which to write
1803 """
1804 if cls in type_maps.inheritance_map:
1805 param = "obj_p"
1806 else:
1807 param = "obj"
1808
1809 out.write("""
1810/**
1811 * Initialize an object of type %(cls)s.
1812 *
1813 * @param obj Pointer to the object to initialize
1814 * @param version The wire version to use for the object
1815 * @param bytes How many bytes in the object
1816 * @param clean_wire Boolean: If true, clear the wire object control struct
1817 *
1818 * If bytes < 0, then the default fixed length is used for the object
1819 *
1820 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07001821 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07001822 *
1823 * If anything other than 0 is passed in for the buffer size, the underlying
1824 * wire buffer will have 'grow' called.
1825 */
1826
1827void
1828%(cls)s_init(%(cls)s_t *%(param)s,
1829 of_version_t version, int bytes, int clean_wire)
1830{
1831""" % dict(cls=cls, param=param))
1832
1833 # Use an extra pointer to deal with inheritance classes
1834 if cls in type_maps.inheritance_map:
1835 out.write("""\
1836 %s_header_t *obj;
1837
1838 obj = &obj_p->header; /* Need instantiable subclass */
1839""" % cls)
1840
1841 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001842 LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001843 if (clean_wire) {
1844 MEMSET(obj, 0, sizeof(*obj));
1845 }
1846 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07001847 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001848 }
1849 obj->version = version;
1850 obj->length = bytes;
1851 obj->object_id = %(enum)s;
1852""" % dict(cls=cls, enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001853
1854 out.write("""
1855 /* Grow the wire buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -07001856 if (obj->wbuf != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001857 int tot_bytes;
1858
Rich Lanecdd542d2014-04-03 16:13:12 -07001859 tot_bytes = bytes + obj->obj_offset;
1860 of_wire_buffer_grow(obj->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -07001861 }
1862}
1863
1864""")
1865
1866## @fixme This should also be updated once there is a map from
1867# class instance to wire length/type accessors
1868def gen_wire_push_fn(cls, out):
1869 """
1870 Generate the calls to push values into the wire buffer
1871 """
1872 if type_maps.class_is_virtual(cls):
1873 print "Push fn gen called for virtual class " + cls
1874 return
1875
1876 out.write("""
1877/**
1878 * Helper function to push values into the wire buffer
1879 */
1880static inline int
1881%(cls)s_push_wire_values(%(cls)s_t *obj)
1882{
1883""" % dict(cls=cls))
1884
Rich Lanebdd8e292013-12-06 17:37:39 -08001885 import loxi_globals
1886 uclass = loxi_globals.unified.class_by_name(cls)
1887 if uclass and not uclass.virtual and uclass.has_type_members:
1888 out.write("""
1889 %(cls)s_push_wire_types(obj);
1890""" % dict(cls=cls))
1891
Rich Lanea06d0c32013-03-25 08:52:03 -07001892 if loxi_utils.class_is_message(cls):
1893 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08001894 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07001895 of_message_t msg;
1896
1897 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001898 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001899 }
1900""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07001901
Rich Lanea06d0c32013-03-25 08:52:03 -07001902 else: # Not a message
1903 if loxi_utils.class_is_tlv16(cls):
1904 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08001905 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07001906 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001907""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001908
Rich Lanea06d0c32013-03-25 08:52:03 -07001909 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
1910 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001911 of_object_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001912""")
1913
1914 if cls == "of_meter_stats":
1915 out.write("""
1916 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
1917""" % dict(enum=enum_name(cls)))
1918
1919 out.write("""
1920 return OF_ERROR_NONE;
1921}
1922""")
1923
1924def gen_new_fn_body(cls, out):
1925 """
1926 Generate function body for new function
1927 @param cls The class name for the function
1928 @param out The file to which to write
1929 """
1930
1931 out.write("""
1932/**
1933 * \\defgroup %(cls)s %(cls)s
1934 */
1935""" % dict(cls=cls))
1936
1937 if not type_maps.class_is_virtual(cls):
1938 gen_wire_push_fn(cls, out)
1939
Rich Lane37911fd2014-04-01 22:11:22 -07001940 uclass = loxi_globals.unified.class_by_name(cls)
1941 is_fixed_length = uclass and uclass.is_fixed_length
1942 max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
1943
Rich Lanea06d0c32013-03-25 08:52:03 -07001944 out.write("""
1945/**
1946 * Create a new %(cls)s object
1947 *
1948 * @param version The wire version to use for the object
1949 * @return Pointer to the newly create object or NULL on error
1950 *
1951 * Initializes the new object with it's default fixed length associating
1952 * a new underlying wire buffer.
1953 *
Rich Lanea06d0c32013-03-25 08:52:03 -07001954 * \\ingroup %(cls)s
1955 */
1956
1957%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08001958%(cls)s_new(of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001959{
1960 %(cls)s_t *obj;
1961 int bytes;
1962
Rich Lanef70be942013-07-18 13:33:14 -07001963 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001964
Rich Lane37911fd2014-04-01 22:11:22 -07001965 if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001966 return NULL;
1967 }
1968
1969 %(cls)s_init(obj, version, bytes, 0);
Rich Lane37911fd2014-04-01 22:11:22 -07001970""" % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
Rich Lanea06d0c32013-03-25 08:52:03 -07001971 if not type_maps.class_is_virtual(cls):
1972 out.write("""
1973 if (%(cls)s_push_wire_values(obj) < 0) {
1974 FREE(obj);
1975 return NULL;
1976 }
1977""" % dict(cls=cls))
1978
1979 match_offset = v3_match_offset_get(cls)
1980 if match_offset >= 0:
1981 # Init length field for match object
1982 out.write("""
1983 /* Initialize match TLV for 1.2 */
1984 /* FIXME: Check 1.3 below */
1985 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
1986 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
1987 }
1988""" % dict(match_offset=match_offset))
1989 out.write("""
1990 return obj;
1991}
Rich Lanea06d0c32013-03-25 08:52:03 -07001992""" % dict(cls=cls))
1993
1994
Rich Lanea06d0c32013-03-25 08:52:03 -07001995################################################################
1996# Now the top level generator functions
1997################################################################
1998
1999def gen_new_function_declarations(out):
2000 """
2001 Gerenate the header file declarations for new operators for all classes
2002 @param out The file to which to write the decs
2003 """
2004
2005 out.write("""
2006/****************************************************************
2007 *
2008 * New operator declarations
2009 *
2010 * _new: Create a new object for writing; includes init
Rich Lanea06d0c32013-03-25 08:52:03 -07002011 * _init: Initialize and optionally allocate buffer space for an
2012 * automatic instance
2013 *
Rich Lanebb8f17c2014-06-12 13:14:09 -07002014 * _new and requires a delete operation to be called on the object.
Rich Lanea06d0c32013-03-25 08:52:03 -07002015 *
2016 ****************************************************************/
2017""")
Rich Lanea06d0c32013-03-25 08:52:03 -07002018
2019 for cls in of_g.standard_class_order:
2020 out.write("""
2021extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002022 %(cls)s_new(of_version_t version);
Rich Lanea06d0c32013-03-25 08:52:03 -07002023""" % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07002024 out.write("""extern void %(cls)s_init(
2025 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2026""" % dict(cls=cls))
2027
2028 out.write("""
2029/****************************************************************
2030 *
2031 * Delete operator static inline definitions.
2032 * These are here for type checking purposes only
2033 *
2034 ****************************************************************/
2035""")
2036 for cls in of_g.standard_class_order:
2037# if cls in type_maps.inheritance_map:
2038# continue
2039 out.write("""
2040/**
2041 * Delete an object of type %(cls)s_t
2042 * @param obj An instance of type %(cls)s_t
2043 *
2044 * \ingroup %(cls)s
2045 */
2046static inline void
2047%(cls)s_delete(%(cls)s_t *obj) {
2048 of_object_delete((of_object_t *)(obj));
2049}
2050""" % dict(cls=cls))
2051
2052 out.write("""
2053typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
2054 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07002055extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07002056""")
2057
2058 out.write("""
2059/****************************************************************
2060 *
2061 * Function pointer initialization functions
2062 * These are part of the "coerce" type casting for objects
2063 *
2064 ****************************************************************/
2065""")
2066
Rich Laneb604e332013-12-15 13:23:51 -08002067def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002068 """
2069 Generate the new operator for all classes
2070
2071 @param out The file to which to write the functions
2072 """
2073
Rich Laneb604e332013-12-15 13:23:51 -08002074 gen_new_fn_body(cls, out)
2075 gen_init_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07002076
Rich Lanea06d0c32013-03-25 08:52:03 -07002077"""
2078Document generation functions
2079
2080The main reason this is here is to generate documentation per
2081accessor that indicates the versions that support the interface.
2082"""
2083
2084
2085def gen_accessor_doc(out, name):
2086 """
2087 Generate documentation for each accessor function that indicates
2088 the versions supporting the accessor.
2089 """
2090
2091 common_top_matter(out, name)
2092
2093 out.write("/* DOCUMENTATION ONLY */\n")
2094
2095 for cls in of_g.standard_class_order:
2096 if cls in type_maps.inheritance_map:
2097 pass # Check this
2098
2099 out.write("""
2100/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002101 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07002102 * accessors available in all versions unless noted otherwise
2103 *
2104""" % dict(cls=cls))
2105 if loxi_utils.class_is_list(cls):
2106 out.write("""\
2107 * @param first Function of type %(cls)s_first_f.
2108 * Setup a TBD class object to the first entry in the list
2109 * @param next Function of type %(cls)s_next_f.
2110 * Advance a TBD class object to the next entry in the list
2111 * @param append_bind Function of type %(cls)s_append_bind_f
2112 * Setup a TBD class object for append to the end of the current list
2113 * @param append Function of type @ref %(cls)s_append_f.
2114 * Copy an item to the end of a list
2115""" % dict(cls=cls))
2116
2117 for m_name in of_g.ordered_members[cls]:
2118 if m_name in of_g.skip_members:
2119 continue
2120 ver_type_map = field_ver_get(cls, m_name)
2121 (m_type, get_rv) = get_acc_rv(cls, m_name)
2122 if len(ver_type_map) == 3:
2123 # ver_string = "Available in all versions"
2124 ver_string = ""
2125 else:
2126 ver_string = "("
2127 for ver in sorted(ver_type_map):
2128 ver_string += " " + of_g.short_version_names[ver]
2129 ver_string += ")."
2130
2131 f_name = acc_name(cls, m_name)
2132 out.write("""\
2133 * @param %(m_name)s_get/set %(ver_string)s
2134 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
2135 * are of type %(f_name)s_get_f and _set_f.
2136 *
2137""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
2138
2139 out.write("""\
2140 */
2141typedef struct %(cls)s_s %(cls)s_t;
2142""" % dict(cls=cls))
2143
2144 out.write("#endif /* _LOCI_DOC_H_ */\n")