blob: 3fa4f3a628216455a96890e473cc99c174785eaf [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)
316 c_match.gen_incompat_members(out)
317 c_match.gen_match_struct(out)
318 c_match.gen_match_comp(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700319 out.write("\n#endif /* Match header file */\n")
320
321def top_h_gen(out, name):
322 """
323 Generate code for
324 @param out The file handle to write to
325 @param name The name of the file
326 """
327 external_h_top_matter(out, name)
328 out.write("""
329
330typedef enum loci_log_level {
331 LOCI_LOG_LEVEL_TRACE,
332 LOCI_LOG_LEVEL_VERBOSE,
333 LOCI_LOG_LEVEL_INFO,
334 LOCI_LOG_LEVEL_WARN,
335 LOCI_LOG_LEVEL_ERROR,
336 LOCI_LOG_LEVEL_MSG
337} loci_log_level_t;
338
339/**
340 * @brief Output a log message.
341 * @param level The log level.
342 * @param fname The function name.
343 * @param file The file name.
344 * @param line The line number.
345 * @param format The message format string.
346 */
347typedef int (*loci_logger_f)(loci_log_level_t level,
348 const char *fname, const char *file, int line,
349 const char *format, ...);
350
351/*
352 * This variable should be set by the user of the library to redirect logs to
353 * their log infrastructure. The default drops all logs.
354 */
355extern loci_logger_f loci_logger;
356
357/**
358 * Map a generic object to the underlying wire buffer
359 *
360 * Treat as private
361 */
362#define OF_OBJECT_TO_MESSAGE(obj) \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700363 ((of_message_t)(WBUF_BUF((obj)->wbuf)))
Rich Lanea06d0c32013-03-25 08:52:03 -0700364
365/**
366 * Macro for the fixed length part of an object
367 *
368 * @param obj The object whose extended length is being calculated
369 * @returns length in bytes of non-variable part of the object
370 */
371#define OF_OBJECT_FIXED_LENGTH(obj) \\
372 (of_object_fixed_len[(obj)->version][(obj)->object_id])
373
374/**
375 * Return the length of the object beyond its fixed length
376 *
377 * @param obj The object whose extended length is being calculated
378 * @returns length in bytes of non-variable part of the object
379 *
380 * Most variable length fields are alone at the end of a structure.
381 * Their length is a simple calculation, just the total length of
382 * the parent minus the length of the non-variable part of the
383 * parent's class type.
384 */
385
386#define OF_OBJECT_VARIABLE_LENGTH(obj) \\
387 ((obj)->length - OF_OBJECT_FIXED_LENGTH(obj))
388
389/* FIXME: Where do these go? */
390/* Low level maps btwn wire version + type and object ids */
391extern int of_message_is_stats_request(int type, int w_ver);
392extern int of_message_is_stats_reply(int type, int w_ver);
393extern int of_message_stats_reply_to_object_id(int stats_type, int w_ver);
394extern int of_message_stats_request_to_object_id(int stats_type, int w_ver);
395extern int of_message_type_to_object_id(int type, int w_ver);
396
397extern int of_wire_buffer_of_match_get(of_object_t *obj, int offset,
398 of_match_t *match);
399extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
400 of_match_t *match, int cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -0700401""")
402
403 # gen_base_types(out)
404
Rich Lanea06d0c32013-03-25 08:52:03 -0700405 gen_flow_add_setup_function_declarations(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700406 out.write("""
407/****************************************************************
408 *
409 * Declarations of maps between on-the-wire type values and LOCI identifiers
410 *
411 ****************************************************************/
Rich Lanec0e20ff2013-12-15 23:40:31 -0800412
413/**
414 * Generic experimenter type value. Applies to all except
415 * top level message: Action, instruction, error, stats, queue_props, oxm
416 */
417#define OF_EXPERIMENTER_TYPE 0xffff
418
419int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
420int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
421
422of_object_id_t of_action_to_object_id(int action, of_version_t version);
423of_object_id_t of_action_id_to_object_id(int action_id, of_version_t version);
424of_object_id_t of_instruction_to_object_id(int instruction, of_version_t version);
Jonathan Stout47832352014-03-03 12:48:23 -0500425of_object_id_t of_instruction_id_to_object_id(int instruction, of_version_t version);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800426of_object_id_t of_queue_prop_to_object_id(int queue_prop, of_version_t version);
427of_object_id_t of_table_feature_prop_to_object_id(int table_feature_prop, of_version_t version);
428of_object_id_t of_meter_band_to_object_id(int meter_band, of_version_t version);
429of_object_id_t of_hello_elem_to_object_id(int hello_elem, of_version_t version);
430of_object_id_t of_stats_reply_to_object_id(int stats_reply, of_version_t version);
431of_object_id_t of_stats_request_to_object_id(int stats_request, of_version_t version);
432of_object_id_t of_error_msg_to_object_id(uint16_t error_msg, of_version_t version);
433of_object_id_t of_flow_mod_to_object_id(int flow_mod, of_version_t version);
434of_object_id_t of_group_mod_to_object_id(int group_mod, of_version_t version);
435of_object_id_t of_oxm_to_object_id(uint32_t type_len, of_version_t version);
436of_object_id_t of_message_experimenter_to_object_id(of_message_t msg, of_version_t version);
437of_object_id_t of_message_to_object_id(of_message_t msg, int length);
Rich Lane713d9282013-12-30 15:21:35 -0800438of_object_id_t of_bsn_tlv_to_object_id(int tlv_type, of_version_t version);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800439
440int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
441
442extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];
443extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700444""")
Rich Lanea06d0c32013-03-25 08:52:03 -0700445 c_type_maps.gen_type_data_header(out)
446 c_match.gen_declarations(out)
447 # @fixme Move debug stuff to own fn
448 out.write("""
449/**
450 * Macro to check consistency of length for top level objects
451 *
452 * If the object has no parent then its length should match the
453 * underlying wire buffer's current bytes.
454 */
455#define OF_LENGTH_CHECK_ASSERT(obj) \\
Rich Lanee57f0432014-02-19 10:31:53 -0800456 LOCI_ASSERT(((obj)->parent != NULL) || \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700457 ((obj)->wbuf == NULL) || \\
458 (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
Rich Lanea06d0c32013-03-25 08:52:03 -0700459
460#define OF_DEBUG_DUMP
461#if defined(OF_DEBUG_DUMP)
462extern void dump_match(of_match_t *match);
463#endif /* OF_DEBUG_DUMP */
464""")
465
466 out.write("\n#endif /* Top header file */\n")
467
468def match_c_gen(out, name):
469 """
470 Generate code for
471 @param out The file handle to write to
472 @param name The name of the file
473 """
474 c_match.match_c_top_matter(out, name)
475 c_match.gen_match_conversions(out)
476 c_match.gen_serialize(out)
477 c_match.gen_deserialize(out)
478
Rich Lanea06d0c32013-03-25 08:52:03 -0700479################################################################
480# Top Matter
481################################################################
482
483def common_top_matter(out, name):
484 loxi_utils.gen_c_copy_license(out)
485 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700486
Rich Lanea06d0c32013-03-25 08:52:03 -0700487/****************************************************************
488 * File: %s
489 *
490 * DO NOT EDIT
491 *
492 * This file is automatically generated
493 *
494 ****************************************************************/
495
496""" % name)
497
498 if name[-2:] == ".h":
499 out.write("""
500#if !defined(%(h)s)
501#define %(h)s
502
503""" % dict(h=h_file_to_define(name)))
504
505def base_h_content(out):
506 """
507 Generate base header file content
508
509 @param out The output file object
510 """
511
512 # @fixme Supported version should be generated based on input to LoxiGen
513
514 out.write("""
515/*
516 * Base OpenFlow definitions. These depend only on standard C headers
517 */
518#include <string.h>
519#include <stdint.h>
520
521/* g++ requires this to pick up PRI, etc.
522 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
523 */
524#if !defined(__STDC_FORMAT_MACROS)
525#define __STDC_FORMAT_MACROS
526#endif
527#include <inttypes.h>
528
529#include <stdlib.h>
530#include <assert.h>
531#include <loci/loci_idents.h>
532
533/**
534 * Macro to enable debugging for LOCI.
535 *
536 * This enables debug output to stdout.
537 */
538#define OF_DEBUG_ENABLE
539
540#if defined(OF_DEBUG_ENABLE)
541#include <stdio.h> /* Currently for debugging */
542#define FIXME(str) do { \\
543 fprintf(stderr, "%s\\n", str); \\
544 exit(1); \\
545 } while (0)
546#define debug printf
547#else
548#define FIXME(str)
549#define debug(str, ...)
550#endif /* OF_DEBUG_ENABLE */
551
552/**
553 * The type of a function used by the LOCI dump/show functions to
554 * output text. Essentially the same signature as fprintf. May
555 * be called many times per invocation of e.g. of_object_show().
556 */
557typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
558
559/**
560 * Check if a version is supported
561 */
562#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
563
564""")
565 gen_version_enum(out)
566 out.write("\n")
567
568 # for c_name in of_g.ofp_constants:
569 # val = str(of_g.ofp_constants[c_name])
570 # out.write("#define %s %s\n" % (c_name, val))
571 # out.write("\n")
572
573 out.write("""
574typedef enum of_error_codes_e {
575 OF_ERROR_NONE = 0,
576 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
577 OF_ERROR_PARAM = -2, /* Bad parameter */
578 OF_ERROR_VERSION = -3, /* Version not supported */
579 OF_ERROR_RANGE = -4, /* End of list indication */
580 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
581 OF_ERROR_PARSE = -6, /* Error in parsing data */
582 OF_ERROR_INIT = -7, /* Uninitialized data */
583 OF_ERROR_UNKNOWN = -8 /* Unknown error */
584} of_error_codes_t;
585
586#define OF_ERROR_STRINGS "none", \\
587 "resource", \\
588 "parameter", \\
589 "version", \\
590 "range", \\
591 "incompatible", \\
592 "parse", \\
593 "init", \\
594 "unknown"
595
Rich Laneb157b0f2013-03-27 13:55:28 -0700596extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700597
Rich Lanea8b54632014-02-19 11:17:47 -0800598#ifdef __GNUC__
599#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
600#else
601#define LOCI_NORETURN_ATTR
602#endif
603
604extern void loci_assert_fail(
605 const char *cond,
606 const char *file,
607 unsigned int line) LOCI_NORETURN_ATTR;
608
Rich Lane53757732013-02-23 17:00:10 -0800609#ifndef NDEBUG
Rich Lanea8b54632014-02-19 11:17:47 -0800610#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
Rich Lane53757732013-02-23 17:00:10 -0800611#else
Rich Lanee57f0432014-02-19 10:31:53 -0800612#define LOCI_ASSERT(val)
Rich Lane53757732013-02-23 17:00:10 -0800613#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700614
615/*
616 * Some LOCI object accessors can fail, and it's easy to forget to check.
617 * On certain compilers we can trigger a warning if the error code
618 * is ignored.
619 */
620#ifndef DISABLE_WARN_UNUSED_RESULT
621#ifdef __GNUC__
622#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
623#else
624#define WARN_UNUSED_RESULT
625#endif
626#else
627#define WARN_UNUSED_RESULT
628#endif
629
630typedef union of_generic_u of_generic_t;
631typedef struct of_object_s of_object_t;
632
633/* Define ipv4 address as uint32 */
634typedef uint32_t of_ipv4_t;
635
636/* Table ID is the OF standard uint8 */
637typedef uint8_t of_table_id_t;
638
639#define OF_MAC_ADDR_BYTES 6
640typedef struct of_mac_addr_s {
641 uint8_t addr[OF_MAC_ADDR_BYTES];
642} of_mac_addr_t;
643
644#define OF_IPV6_BYTES 16
645typedef struct of_ipv6_s {
646 uint8_t addr[OF_IPV6_BYTES];
647} of_ipv6_t;
648
649extern const of_mac_addr_t of_mac_addr_all_ones;
650extern const of_mac_addr_t of_mac_addr_all_zeros;
651
652extern const of_ipv6_t of_ipv6_all_ones;
653extern const of_ipv6_t of_ipv6_all_zeros;
654
655/**
656 * Generic zero and all-ones values of size 16 bytes.
657 *
658 * IPv6 is longest data type we worry about for comparisons
659 */
660#define of_all_zero_value of_ipv6_all_zeros
661#define of_all_ones_value of_ipv6_all_ones
662
663/**
664 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
665 */
666#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
667 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
668#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
669 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
670
671/* The octets object is a struct holding pointer and length */
672typedef struct of_octets_s {
673 uint8_t *data;
674 int bytes;
675} of_octets_t;
676
677/* Macro to convert an octet object to a pointer; currently trivial */
678#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
679#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
680#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
681#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
682
683/* Currently these are categorized as scalars */
684typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
685typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
686typedef char of_desc_str_t[OF_DESC_STR_LEN];
687typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
Rich Lanef8a3d002014-03-19 13:33:52 -0700688typedef char of_str64_t[64];
Rich Lanea06d0c32013-03-25 08:52:03 -0700689
Rich Lane3b2fd832013-09-24 13:44:08 -0700690typedef struct of_bitmap_128_s {
691 uint64_t hi;
692 uint64_t lo;
693} of_bitmap_128_t;
694
Rich Lanefab0c822013-12-30 11:46:48 -0800695typedef struct of_checksum_128_s {
696 uint64_t hi;
697 uint64_t lo;
698} of_checksum_128_t;
699
Rich Lanea06d0c32013-03-25 08:52:03 -0700700/* These are types which change across versions. */
701typedef uint32_t of_port_no_t;
702typedef uint16_t of_fm_cmd_t;
703typedef uint64_t of_wc_bmap_t;
704typedef uint64_t of_match_bmap_t;
705
706#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
707#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
708#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
709#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
710#define MALLOC(bytes) malloc(bytes)
711#define FREE(ptr) free(ptr)
712
713/** Try an operation and return on failure. */
714#define OF_TRY(op) do { \\
715 int _rv; \\
716 if ((_rv = (op)) < 0) { \\
717 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
718 return _rv; \\
719 } \\
720 } while (0)
721
722/* The extent of an OF match object is determined by its length field, but
723 * aligned to 8 bytes
724 */
725
726#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
727
Rich Lanedfcafae2014-03-06 16:56:49 -0800728#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
Rich Lanea06d0c32013-03-25 08:52:03 -0700729#define U16_NTOH(val) (val)
730#define U32_NTOH(val) (val)
731#define U64_NTOH(val) (val)
732#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
733#define U16_HTON(val) (val)
734#define U32_HTON(val) (val)
735#define U64_HTON(val) (val)
736#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
737#else /* Little Endian */
Rich Lane69e247e2014-03-05 10:27:22 -0800738#define U16_NTOH(val) (((val) >> 8) | (((val) & 0xff) << 8))
Rich Lanea06d0c32013-03-25 08:52:03 -0700739#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
740 (((val) & 0x00ff0000) >> 8) | \\
741 (((val) & 0x0000ff00) << 8) | \\
742 (((val) & 0x000000ff) << 24))
743#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
744 (((val) & 0x00ff000000000000LL) >> 40) | \\
745 (((val) & 0x0000ff0000000000LL) >> 24) | \\
746 (((val) & 0x000000ff00000000LL) >> 8) | \\
747 (((val) & 0x00000000ff000000LL) << 8) | \\
748 (((val) & 0x0000000000ff0000LL) << 24) | \\
749 (((val) & 0x000000000000ff00LL) << 40) | \\
750 (((val) & 0x00000000000000ffLL) << 56))
751#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
752#define U16_HTON(val) U16_NTOH(val)
753#define U32_HTON(val) U32_NTOH(val)
754#define U64_HTON(val) U64_NTOH(val)
755#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
756#endif
757
758/****************************************************************
759 *
760 * The following are internal definitions used by the automatically
761 * generated code. Users should not reference these definitions
762 * as they may change between versions of this code
763 *
764 ****************************************************************/
765
766#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
767 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
768#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
769#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
770 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
771
772#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
773 (FIXED_LEN + of_message_out_actions_len_get(obj))
774
775""")
776
777def external_h_top_matter(out, name):
778 """
779 Generate top matter for external header file
780
781 @param name The name of the output file
782 @param out The output file object
783 """
784 common_top_matter(out, name)
785 out.write("""
786#include <loci/loci_base.h>
787#include <loci/of_message.h>
788#include <loci/of_match.h>
789#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800790#include <loci/loci_classes.h>
Rich Lanedc46fe22014-04-03 15:10:38 -0700791#include <loci/loci_class_metadata.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700792
793/****************************************************************
794 *
795 * This file is divided into the following sections.
796 *
797 * A few object specific macros
798 * Class typedefs (no struct definitions)
799 * Per-data type accessor function typedefs
800 * Per-class new/delete function typedefs
801 * Per-class static delete functions
802 * Per-class, per-member accessor declarations
803 * Per-class structure definitions
804 * Generic union (inheritance) definitions
805 * Pointer set function declarations
806 * Some special case macros
807 *
808 ****************************************************************/
809""")
810
Rich Lanea06d0c32013-03-25 08:52:03 -0700811################################################################
812#
813################################################################
814
815def gen_version_enum(out):
816 """
817 Generate the enumerated type for versions in LoxiGen
818 @param out The file object to which to write the decs
819
820 This just uses the wire versions for now
821 """
822 out.write("""
823/**
824 * Enumeration of OpenFlow versions
825 *
826 * The wire protocol numbers are currently used for values of the corresponding
827 * version identifiers.
828 */
829typedef enum of_version_e {
830 OF_VERSION_UNKNOWN = 0,
831""")
832
833 is_first = True
834 max = 0
835 for v in of_g.wire_ver_map:
836 if is_first:
837 is_first = False
838 else:
839 out.write(",\n")
840 if v > max:
841 max = v
842 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
843
844 out.write("""
845} of_version_t;
846
847/**
848 * @brief Use this when declaring arrays indexed by wire version
849 */
850#define OF_VERSION_ARRAY_MAX %d
851""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700852
Rich Lanea06d0c32013-03-25 08:52:03 -0700853def gen_object_enum(out):
854 """
855 Generate the enumerated type for object identification in LoxiGen
856 @param out The file object to which to write the decs
857 """
858 out.write("""
859
860/**
861 * Enumeration of OpenFlow objects
862 *
863 * We enumerate the OpenFlow objects used internally. Note that some
864 * message types are determined both by an outer type (message type like
865 * stats_request) and an inner type (port stats). These are different
866 * messages in ofC.
867 *
868 * These values are for internal use only. They will change with
869 * different versions of ofC.
870 */
871
872typedef enum of_object_id_e {
873 /* Root object type */
874 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
875 OF_OBJECT = 0, /* Generic, untyped object */
876
877 /* OpenFlow message objects */
878""")
879 last = 0
880 msg_count = 0
881 for cls in of_g.ordered_messages:
882 out.write(" %s = %d,\n" % (enum_name(cls),
883 of_g.unified[cls]["object_id"]))
884 msg_count = of_g.unified[cls]["object_id"] + 1
885
886 out.write("\n /* Non-message objects */\n")
887 for cls in of_g.ordered_non_messages:
888 out.write(" %s = %d,\n" % (enum_name(cls),
889 of_g.unified[cls]["object_id"]))
890 last = of_g.unified[cls]["object_id"]
891 out.write("\n /* List objects */\n")
892 for cls in of_g.ordered_list_objects:
893 out.write(" %s = %d,\n" % (enum_name(cls),
894 of_g.unified[cls]["object_id"]))
895 last = of_g.unified[cls]["object_id"]
896
Rich Lanea06d0c32013-03-25 08:52:03 -0700897 out.write("""
898 OF_OBJECT_COUNT = %d
899} of_object_id_t;
900
Rich Laneb157b0f2013-03-27 13:55:28 -0700901extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700902
903#define OF_MESSAGE_OBJECT_COUNT %d
904""" % ((last + 1), msg_count))
905
906 # Generate object type range checking for inheritance classes
907
908 # @fixme These should be determined algorithmicly
909 out.write("""
910/*
911 * Macros to check if an object ID is within an inheritance class range
912 */
913""")
914 # Alphabetical order for 'last'
915 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
916 of_oxm="OF_OXM_VLAN_VID_MASKED",
917 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
918 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
919 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
920 # @FIXME add meter_band ?
921 )
922 for cls, last in last_ids.items():
923 out.write("""
924#define %(enum)s_FIRST_ID (%(enum)s + 1)
925#define %(enum)s_LAST_ID %(last)s
926#define %(enum)s_VALID_ID(id) \\
927 ((id) >= %(enum)s_FIRST_ID && \\
928 (id) <= %(enum)s_LAST_ID)
929""" % dict(enum=enum_name(cls), last=last))
930 out.write("""
931/**
932 * Function to check a wire ID
933 * @param object_id The ID to check
934 * @param base_object_id The inheritance parent, if applicable
935 * @returns boolean: If base_object_id is an inheritance class, check if
936 * object_id is valid as a subclass. Otherwise return 1.
937 *
938 * Note: Could check that object_id == base_object_id in the
939 * second case.
940 */
941static inline int
942of_wire_id_valid(int object_id, int base_object_id) {
943 switch (base_object_id) {
944 case OF_ACTION:
945 return OF_ACTION_VALID_ID(object_id);
946 case OF_OXM:
947 return OF_OXM_VALID_ID(object_id);
948 case OF_QUEUE_PROP:
949 return OF_QUEUE_PROP_VALID_ID(object_id);
950 case OF_TABLE_FEATURE_PROP:
951 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
952 case OF_INSTRUCTION:
953 return OF_INSTRUCTION_VALID_ID(object_id);
954 default:
955 break;
956 }
957 return 1;
958}
959""")
960
Rich Lanea06d0c32013-03-25 08:52:03 -0700961################################################################
962#
963# Internal Utility Functions
964#
965################################################################
966
967
968def acc_name(cls, m_name):
969 """
970 Generate the root name of an accessor function for typedef
971 @param cls The class name
972 @param m_name The member name
973 """
974 (m_type, get_rv) = get_acc_rv(cls, m_name)
975 return "%s_%s" % (cls, m_type)
976
977def get_acc_rv(cls, m_name):
978 """
979 Determine the data type and return type for a get accessor.
980
981 The return type may be "void" or it may be the accessor type
982 depending on the system configuration and on the data type.
983
984 @param cls The class name
985 @param m_name The member name
986 @return A pair (m_type, rv) where m_type is the unified type of the
987 member and rv is the get_accessor return type
988 """
989 member = of_g.unified[cls]["union"][m_name]
990 m_type = member["m_type"]
991 rv = "int"
Rich Lanea06d0c32013-03-25 08:52:03 -0700992 if m_type[-2:] == "_t":
993 m_type = m_type[:-2]
994
995 return (m_type, rv)
996
997def param_list(cls, m_name, a_type):
998 """
999 Generate the parameter list (no parens) for an a_type accessor
1000 @param cls The class name
1001 @param m_name The member name
1002 @param a_type One of "set" or "get" or TBD
1003 """
1004 member = of_g.unified[cls]["union"][m_name]
1005 m_type = member["m_type"]
1006 params = ["%s_t *obj" % cls]
1007 if a_type == "set":
1008 if loxi_utils.type_is_scalar(m_type):
1009 params.append("%s %s" % (m_type, m_name))
1010 else:
1011 params.append("%s *%s" % (m_type, m_name))
1012 elif a_type in ["get", "bind"]:
1013 params.append("%s *%s" % (m_type, m_name))
1014 else:
1015 debug("Class %s, name %s Bad param list a_type: %s" %
1016 (cls, m_name, a_type))
1017 sys.exit(1)
1018 return params
1019
Rich Lanea06d0c32013-03-25 08:52:03 -07001020def field_ver_get(cls, m_name):
1021 """
1022 Generate a dict, indexed by wire version, giving a pair (type, offset)
1023
1024 @param cls The class name
1025 @param m_name The name of the class member
1026
1027 If offset is not known for m_name, the type
1028 A dict is used for more convenient indexing.
1029 """
1030 result = {}
1031
1032 for ver in of_g.unified[cls]:
1033 if type(ver) == type(0): # It's a version
1034 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1035 ref_ver = of_g.unified[cls][ver]["use_version"]
1036 members = of_g.unified[cls][ref_ver]["members"]
1037 else:
1038 members = of_g.unified[cls][ver]["members"]
1039 idx = loxi_utils.member_to_index(m_name, members)
1040 if (idx < 0):
1041 continue # Member not in this version
1042 m_type = members[idx]["m_type"]
1043 offset = members[idx]["offset"]
1044
1045 # If m_type is mixed, get wire version type from global data
1046 if m_type in of_g.of_mixed_types and \
1047 ver in of_g.of_mixed_types[m_type]:
1048 m_type = of_g.of_mixed_types[m_type][ver]
1049
1050 # add version to result list
1051 result[ver] = (m_type, offset)
1052
1053 return result
1054
1055def v3_match_offset_get(cls):
1056 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001057 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001058 otherwise return -1
1059 """
1060 result = field_ver_get(cls, "match")
1061 if of_g.VERSION_1_2 in result:
1062 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1063 return result[of_g.VERSION_1_2][1]
1064 return -1
1065
1066################################################################
1067#
1068# OpenFlow Object Definitions
1069#
1070################################################################
1071
Rich Lanea06d0c32013-03-25 08:52:03 -07001072def gen_generics(out):
1073 for (cls, subclasses) in type_maps.inheritance_map.items():
1074 out.write("""
1075/**
1076 * Inheritance super class for %(cls)s
1077 *
1078 * This class is the union of %(cls)s classes. You can refer
1079 * to it untyped by refering to the member 'header' whose structure
1080 * is common across all sub-classes.
1081 */
1082
1083union %(cls)s_u {
1084 %(cls)s_header_t header; /* Generic instance */
1085""" % dict(cls=cls))
1086 for subcls in sorted(subclasses):
1087 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1088 out.write("};\n")
1089
1090def gen_struct_typedefs(out):
1091 """
1092 Generate typedefs for all struct objects
1093 @param out The file for output, already open
1094 """
1095
1096 out.write("\n/* LOCI inheritance parent typedefs */\n")
1097 for cls in type_maps.inheritance_map:
1098 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1099 out.write("\n/* LOCI object typedefs */\n")
1100 for cls in of_g.standard_class_order:
1101 if cls in type_maps.inheritance_map:
1102 continue
Rich Lane85767872013-12-15 16:24:42 -08001103 template = "typedef of_object_t %(cls)s_t;\n"
1104 out.write(template % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001105
1106 out.write("""
1107/****************************************************************
1108 *
1109 * Additional of_object defines
1110 * These are needed for some static inline ops, so we put them here.
1111 *
1112 ****************************************************************/
1113
1114/* Delete an OpenFlow object without reference to its type */
1115extern void of_object_delete(of_object_t *obj);
1116
1117""")
1118
Rich Lanea06d0c32013-03-25 08:52:03 -07001119def gen_flow_add_setup_function_declarations(out):
1120 """
1121 Add the declarations for functions that can be initialized
1122 by a flow add. These are defined external to LOXI.
1123 """
1124
1125 out.write("""
1126/****************************************************************
1127 * Functions for objects that can be initialized by a flow add message.
1128 * These are defined in a non-autogenerated file
1129 ****************************************************************/
1130
1131/**
1132 * @brief Set up a flow removed message from the original add
1133 * @param obj The flow removed message being updated
1134 * @param flow_add The flow_add message to use
1135 *
1136 * Initialize the following fields of obj to be identical
1137 * to what was originally on the wire from the flow_add object:
1138 * match
1139 * cookie
1140 * priority
1141 * idle_timeout
1142 * hard_timeout
1143 *
1144 */
1145
1146extern int
1147of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1148 of_flow_add_t *flow_add);
1149
1150
1151/**
1152 * @brief Set up the packet in match structure from the original add
1153 * @param obj The packet in message being updated
1154 * @param flow_add The flow_add message to use
1155 * @returns Indigo error code. Does not return a version error if
1156 * the version does not require initializing obj.
1157 *
1158 * Initialize the match member of obj to be identical to what was originally
1159 * on the wire from the flow_add object. If applicable, the table ID is also
1160 * initialized from the flow_add object.
1161 *
1162 * This API applies to 1.2 and later only.
1163 */
1164
1165extern int
1166of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1167 of_flow_add_t *flow_add);
1168
1169
1170/**
1171 * @brief Set up the flow stats entry from the original add
1172 * @param obj The packet in message being updated
1173 * @param flow_add The flow_add message to use
1174 * @param effects Optional actions or instructions; see below.
1175 *
1176 * Initialize the following fields of obj to be identical
1177 * to what was originally on the wire from the flow_add object:
1178 * match
1179 * actions/instructions (effects)
1180 * cookie
1181 * priority
1182 * idle_timeout
1183 * hard_timeout
1184 *
Andreas Wundsam53256162013-05-02 14:05:53 -07001185 * Note that the actions/instructions of a flow may be modified by a
Rich Lanea06d0c32013-03-25 08:52:03 -07001186 * subsequent flow modify message. To facilitate implementations,
1187 * the "effects" parameter is provided. If effects is NULL, the
1188 * actions/instructions are taken from the flow_add message.
1189 * Otherwise, effects is coerced to the proper type (actions or
1190 * instructions) and used to init obj.
1191 */
1192
1193extern int
1194of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1195 of_flow_add_t *flow_add,
1196 of_object_t *effects);
1197""")
1198
Rich Lanea06d0c32013-03-25 08:52:03 -07001199################################################################
1200#
1201# List accessor code generation
1202#
1203# Currently these all implement copy on read semantics
1204#
1205################################################################
1206
1207def init_call(e_type, obj, ver, length, cw):
1208 """
1209 Generate the init call given the strings for params
1210 """
1211 hdr = "" # If inheritance type, coerce to hdr object
1212 obj_name = obj
1213 if e_type in type_maps.inheritance_map:
1214 hdr = "_header"
1215 obj_name = "(%s_header_t *)" % e_type + obj
1216
1217 return """\
1218%(e_type)s%(hdr)s_init(%(obj_name)s,
1219 %(ver)s, %(length)s, %(cw)s)\
1220""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1221 length=length, cw=cw)
1222
1223def gen_list_first(out, cls, e_type):
1224 """
1225 Generate the body of a list_first operation
1226 @param cls The class name for which code is being generated
1227 @param e_type The element type of the list
1228 @param out The file to which to write
1229 """
1230 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1231 if e_type in type_maps.inheritance_map:
1232 len_str = "obj->header.length"
1233 else:
1234 len_str = "obj->length"
1235
1236 out.write("""
1237/**
1238 * Associate an iterator with a list
1239 * @param list The list to iterate over
1240 * @param obj The list entry iteration pointer
1241 * @return OF_ERROR_RANGE if the list is empty (end of list)
1242 *
1243 * The obj instance is completely initialized. The caller is responsible
1244 * for cleaning up any wire buffers associated with obj before this call
1245 */
1246
1247int
1248%(cls)s_first(%(cls)s_t *list,
1249 %(e_type)s_t *obj)
1250{
1251 int rv;
1252
1253 %(i_call)s;
1254 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1255 return rv;
1256 }
1257""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1258
1259 # Special case flow_stats_entry lists
1260
1261 out.write("""
1262 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1263 list->length);
1264 if (%(len_str)s == 0) {
1265 return OF_ERROR_PARSE;
1266 }
1267
1268 return rv;
1269}
1270""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1271
Rich Lanea06d0c32013-03-25 08:52:03 -07001272def gen_list_next(out, cls, e_type):
1273 """
1274 Generate the body of a list_next operation
1275 @param cls The class name for which code is being generated
1276 @param e_type The element type of the list
1277 @param out The file to which to write
1278 """
1279
1280 if e_type in type_maps.inheritance_map:
1281 len_str = "obj->header.length"
1282 else:
1283 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001284
Rich Lanea06d0c32013-03-25 08:52:03 -07001285 out.write("""
1286/**
1287 * Advance an iterator to the next element in a list
1288 * @param list The list being iterated
1289 * @param obj The list entry iteration pointer
1290 * @return OF_ERROR_RANGE if already at the last entry on the list
1291 *
1292 */
1293
1294int
1295%(cls)s_next(%(cls)s_t *list,
1296 %(e_type)s_t *obj)
1297{
1298 int rv;
1299
1300 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1301 return rv;
1302 }
1303
1304 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1305 list->length);
1306
1307 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1308 return OF_ERROR_PARSE;
1309 }
1310
1311 return rv;
1312}
1313""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1314
1315def gen_list_append(out, cls, e_type):
1316 """
1317 Generate the body of a list append functions
1318 @param cls The class name for which code is being generated
1319 @param e_type The element type of the list
1320 @param out The file to which to write
1321 """
1322
1323 out.write("""
1324/**
1325 * Set up to append an object of type %(e_type)s to an %(cls)s.
1326 * @param list The list that is prepared for append
1327 * @param obj Pointer to object to hold data to append
1328 *
1329 * The obj instance is completely initialized. The caller is responsible
1330 * for cleaning up any wire buffers associated with obj before this call.
1331 *
1332 * See the generic documentation for of_list_append_bind.
1333 */
1334
1335int
1336%(cls)s_append_bind(%(cls)s_t *list,
1337 %(e_type)s_t *obj)
1338{
1339 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1340}
1341
1342/**
1343 * Append an item to a %(cls)s list.
1344 *
1345 * This copies data from item and leaves item untouched.
1346 *
1347 * See the generic documentation for of_list_append.
1348 */
1349
1350int
1351%(cls)s_append(%(cls)s_t *list,
1352 %(e_type)s_t *item)
1353{
1354 return of_list_append((of_object_t *)list, (of_object_t *)item);
1355}
1356
1357""" % dict(cls=cls, e_type=e_type))
1358
1359def gen_list_accessors(out, cls):
1360 e_type = loxi_utils.list_to_entry_type(cls)
1361 gen_list_first(out, cls, e_type)
1362 gen_list_next(out, cls, e_type)
1363 gen_list_append(out, cls, e_type)
1364
1365################################################################
1366#
1367# Accessor Functions
1368#
1369################################################################
1370
Andreas Wundsam53256162013-05-02 14:05:53 -07001371
Rich Lanea06d0c32013-03-25 08:52:03 -07001372def gen_accessor_declarations(out):
1373 """
1374 Generate the declaration of each version independent accessor
1375
1376 @param out The file to which to write the decs
1377 """
1378
1379 out.write("""
1380/****************************************************************
1381 *
1382 * Unified, per-member accessor function declarations
1383 *
1384 ****************************************************************/
1385""")
1386 for cls in of_g.standard_class_order:
1387 if cls in type_maps.inheritance_map:
1388 continue
1389 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1390 for m_name in of_g.ordered_members[cls]:
1391 if m_name in of_g.skip_members:
1392 continue
1393 m_type = loxi_utils.member_base_type(cls, m_name)
1394 base_name = "%s_%s" % (cls, m_name)
1395 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1396 get_ret_type = accessor_return_type("get", m_type)
1397 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1398 set_ret_type = accessor_return_type("set", m_type)
1399 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1400 bind_ret_type = accessor_return_type("bind", m_type)
1401
1402 if loxi_utils.type_is_of_object(m_type):
1403 # Generate bind accessors, but not get accessor
1404 out.write("""
1405extern %(set_ret_type)s %(base_name)s_set(
1406 %(sparams)s);
1407extern %(bind_ret_type)s %(base_name)s_bind(
1408 %(bparams)s);
1409extern %(m_type)s *%(cls)s_%(m_name)s_get(
1410 %(cls)s_t *obj);
1411""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1412 m_name=m_name, m_type=m_type, cls=cls,
1413 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1414 else:
1415 out.write("""
1416extern %(set_ret_type)s %(base_name)s_set(
1417 %(sparams)s);
1418extern %(get_ret_type)s %(base_name)s_get(
1419 %(gparams)s);
1420""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1421 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001422
Rich Lanea06d0c32013-03-25 08:52:03 -07001423 if loxi_utils.class_is_list(cls):
1424 e_type = loxi_utils.list_to_entry_type(cls)
1425 out.write("""
1426extern int %(cls)s_first(
1427 %(cls)s_t *list, %(e_type)s_t *obj);
1428extern int %(cls)s_next(
1429 %(cls)s_t *list, %(e_type)s_t *obj);
1430extern int %(cls)s_append_bind(
1431 %(cls)s_t *list, %(e_type)s_t *obj);
1432extern int %(cls)s_append(
1433 %(cls)s_t *list, %(e_type)s_t *obj);
1434
1435/**
1436 * Iteration macro for list of type %(cls)s
1437 * @param list Pointer to the list being iterated over of
1438 * type %(cls)s
1439 * @param elt Pointer to an element of type %(e_type)s
1440 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1441 */
1442#define %(u_cls)s_ITER(list, elt, rv) \\
1443 for ((rv) = %(cls)s_first((list), (elt)); \\
1444 (rv) == OF_ERROR_NONE; \\
1445 (rv) = %(cls)s_next((list), (elt)))
1446""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1447
1448
1449def wire_accessor(m_type, a_type):
1450 """
1451 Returns the name of the a_type accessor for low level wire buff offset
1452 @param m_type The member type
1453 @param a_type The accessor type (set or get)
1454 """
1455 # Strip off _t if present
1456 if m_type in of_g.of_base_types:
1457 m_type = of_g.of_base_types[m_type]["short_name"]
1458 if m_type in of_g.of_mixed_types:
1459 m_type = of_g.of_mixed_types[m_type]["short_name"]
1460 if m_type[-2:] == "_t":
1461 m_type = m_type[:-2]
1462 if m_type == "octets":
1463 m_type = "octets_data"
1464 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1465
Rich Lane713d9282013-12-30 15:21:35 -08001466def get_len_macro(cls, m_name, m_type, version):
Rich Lanea06d0c32013-03-25 08:52:03 -07001467 """
1468 Get the length macro for m_type in cls
1469 """
1470 if m_type.find("of_match") == 0:
1471 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1472 if m_type.find("of_list_oxm") == 0:
1473 return "wire_match_len(obj, 0) - 4"
1474 if loxi_utils.class_is_tlv16(m_type):
1475 return "_TLV16_LEN(obj, offset)"
1476 if cls == "of_packet_out" and m_type == "of_list_action_t":
1477 return "_PACKET_OUT_ACTION_LEN(obj)"
Rich Lane713d9282013-12-30 15:21:35 -08001478 if cls == "of_bsn_gentable_entry_add" and m_name == "key":
1479 return "of_object_u16_get(obj, 18)"
1480 if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
1481 return "of_object_u16_get(obj, 2)"
1482 if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
1483 return "of_object_u16_get(obj, 2)"
Rich Lanea06d0c32013-03-25 08:52:03 -07001484 # Default is everything to the end of the object
1485 return "_END_LEN(obj, offset)"
1486
1487def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1488 """
1489 Generate the sub-object offset and length calculations for accessors
1490 @param out File being written
1491 @param m_name Name of member
1492 @param version Wire version being processed
1493 @param a_type The accessor type (set or get)
1494 @param m_type The original member type
1495 @param offset The offset of the object or -1 if not fixed
1496 """
1497 # determine offset
1498 o_str = "%d" % offset # Default is fixed length
1499 if offset == -1:
1500 # There are currently 4 special cases for this
1501 # In general, get offset and length of predecessor
1502 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1503 pass
1504 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1505 pass
1506 elif (cls == "of_packet_in" and m_name == "data"):
1507 pass
1508 elif (cls == "of_packet_out" and m_name == "data"):
1509 pass
Rich Lane713d9282013-12-30 15:21:35 -08001510 elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
1511 pass
1512 elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
1513 pass
1514 elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
1515 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001516 else:
1517 debug("Error: Unknown member with offset == -1")
1518 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1519 sys.exit(1)
1520 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1521
1522 out.write("""\
1523 offset = %s;
1524""" % o_str);
1525
1526 # This could be moved to main body but for version check
1527 if not loxi_utils.type_is_scalar(m_type):
1528 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1529 m_type == "of_match_t":
Rich Lane713d9282013-12-30 15:21:35 -08001530 len_macro = get_len_macro(cls, m_name, m_type, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001531 else:
1532 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1533 out.write(" cur_len = %s;\n" % len_macro)
1534 out.write(" break;\n")
1535
1536def length_of(m_type, version):
1537 """
1538 Return the length of a type based on the version
1539 """
1540 if m_type in of_g.of_mixed_types:
1541 m_type = of_g.of_mixed_types[m_type][version]
1542 if m_type in of_g.of_base_types:
1543 return of_g.of_base_types[m_type]["bytes"]
1544 if (m_type[:-2], version) in of_g.base_length:
1545 return of_g.base_length[(m_type[:-2], version)]
1546 print "Unknown length request", m_type, version
1547 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001548
Rich Lanea06d0c32013-03-25 08:52:03 -07001549
1550def gen_get_accessor_body(out, cls, m_type, m_name):
1551 """
1552 Generate the common operations for a get accessor
1553 """
1554 if loxi_utils.type_is_scalar(m_type):
1555 ver = "" # See if version required for scalar update
1556 if m_type in of_g.of_mixed_types:
1557 ver = "ver, "
1558 out.write("""\
1559 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1560""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1561
1562 if m_type == "of_port_no_t":
1563 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1564 elif m_type == "of_octets_t":
1565 out.write("""\
Rich Lanee57f0432014-02-19 10:31:53 -08001566 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001567 %(m_name)s->bytes = cur_len;
1568 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1569""" % dict(m_name=m_name))
1570 elif m_type == "of_match_t":
1571 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001572 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001573 match_octets.bytes = cur_len;
1574 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
1575 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
1576""" % dict(m_name=m_name))
Rich Lane90020b42014-04-07 12:05:45 -07001577 elif m_type == "of_oxm_header_t":
1578 out.write("""
1579 /* Initialize child */
1580 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1581 /* Attach to parent */
1582 %(m_name)s->parent = (of_object_t *)obj;
1583 %(m_name)s->wbuf = obj->wbuf;
1584 %(m_name)s->obj_offset = abs_offset;
1585 %(m_name)s->length = cur_len;
1586 of_object_wire_init(%(m_name)s, OF_OXM, 0);
1587""" % dict(m_type=m_type[:-2], m_name=m_name))
Wilson Ngd6181882014-04-14 16:28:35 -07001588 elif m_type == "of_bsn_vport_header_t":
1589 out.write("""
1590 /* Initialize child */
1591 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1592 /* Attach to parent */
1593 %(m_name)s->parent = (of_object_t *)obj;
1594 %(m_name)s->wbuf = obj->wbuf;
1595 %(m_name)s->obj_offset = abs_offset;
1596 %(m_name)s->length = cur_len;
1597 of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
1598""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001599 else:
1600 out.write("""
1601 /* Initialize child */
1602 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1603 /* Attach to parent */
1604 %(m_name)s->parent = (of_object_t *)obj;
Rich Lanecdd542d2014-04-03 16:13:12 -07001605 %(m_name)s->wbuf = obj->wbuf;
1606 %(m_name)s->obj_offset = abs_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -07001607 %(m_name)s->length = cur_len;
1608""" % dict(m_type=m_type[:-2], m_name=m_name))
1609
1610
1611def gen_set_accessor_body(out, cls, m_type, m_name):
1612 """
1613 Generate the contents of a set accessor
1614 """
1615 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1616 ver = "" # See if version required for scalar update
1617 if m_type in of_g.of_mixed_types:
1618 ver = "ver, "
1619 cur_len = "" # See if version required for scalar update
1620 if m_type == "of_octets_t":
1621 cur_len = ", cur_len"
1622 out.write("""\
1623 new_len = %(m_name)s->bytes;
1624 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1625""" % dict(m_name=m_name))
1626 out.write("""\
1627 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1628""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1629 m_name=m_name))
1630
1631 elif m_type == "of_match_t":
1632 out.write("""
1633 /* Match object */
1634 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1635 new_len = match_octets.bytes;
1636 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1637 match_octets.data, new_len);
1638 /* Free match serialized octets */
1639 FREE(match_octets.data);
1640""" % dict(m_name=m_name))
1641
1642 else: # Other object type
1643 out.write("\n /* LOCI object type */")
1644 # Need to special case OXM list
1645 out.write("""
1646 new_len = %(m_name)s->length;
1647 /* If underlying buffer already shared; nothing to do */
Rich Lanecdd542d2014-04-03 16:13:12 -07001648 if (obj->wbuf == %(m_name)s->wbuf) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001649 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1650 /* Verify that the offsets are correct */
Rich Lanee57f0432014-02-19 10:31:53 -08001651 LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1652 /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
Rich Lanea06d0c32013-03-25 08:52:03 -07001653 return %(ret_success)s;
1654 }
1655
1656 /* Otherwise, replace existing object in data buffer */
1657 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1658 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1659""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1660
1661 if not loxi_utils.type_is_scalar(m_type):
1662 if cls == "of_packet_out" and m_type == "of_list_action_t":
1663 out.write("""
1664 /* Special case for setting action lengths */
1665 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1666""" % dict(m_name=m_name))
Rich Lane713d9282013-12-30 15:21:35 -08001667 elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
1668 out.write("""
1669 /* Special case for setting key length */
1670 of_object_u16_set(obj, 18, %(m_name)s->length);
1671""" % dict(m_name=m_name))
1672 elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
1673 out.write("""
1674 /* Special case for setting key length */
1675 of_object_u16_set(obj, 2, %(m_name)s->length);
1676""" % dict(m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001677 elif m_type not in ["of_match_t", "of_octets_t"]:
1678 out.write("""
1679 /* @fixme Shouldn't this precede copying value's data to buffer? */
Rich Lanedc46fe22014-04-03 15:10:38 -07001680 of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001681""" % dict(m_name=m_name))
1682 out.write("""
1683 /* Not scalar, update lengths if needed */
1684 delta = new_len - cur_len;
1685 if (delta != 0) {
1686 /* Update parent(s) */
1687 of_object_parent_length_update((of_object_t *)obj, delta);
1688 }
1689""")
1690
1691def obj_assert_check(cls):
1692 """
1693 The body of the assert check for an accessor
1694 We allow all versions of add/delete/modify to use the same accessors
1695 """
1696 if cls in ["of_flow_modify", "of_flow_modify_strict",
1697 "of_flow_delete", "of_flow_delete_strict",
1698 "of_flow_add"]:
1699 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1700 else:
1701 return "obj->object_id == %s" % cls.upper()
1702
1703def gen_of_object_get(out, cls, m_name, m_type):
1704 sub_cls = m_type[:-2]
1705 out.write("""
1706/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001707 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001708 * a %(cls)s instance.
1709 *
1710 * @param obj Pointer to the source of type %(cls)s_t
1711 * @returns A pointer to a new instance of type %(m_type)s whose contents
1712 * match that of %(m_name)s from source
1713 * @returns NULL if an error occurs
1714 */
1715%(m_type)s *
1716%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1717 %(m_type)s _%(m_name)s;
1718 %(m_type)s *_%(m_name)s_ptr;
1719
1720 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1721 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1722 return _%(m_name)s_ptr;
1723}
1724""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1725
1726def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1727 """
1728 Generate the body of a set or get accessor function
1729
1730 @param out The file to which to write the decs
1731 @param cls The class name
1732 @param m_name The member name
1733 @param ver_type_map Maps (type, offset) pairs to a list of versions
1734 @param a_type The accessor type, set or get
1735 @param m_type The original member type
1736
1737 The type values in ver_type_map are now ignored as we've pushed down
1738 the type munging to the lower level.
1739
1740 This is unified because the version switch case processing is the
1741 same for both set and get
1742 """
1743 out.write("""{
1744 of_wire_buffer_t *wbuf;
1745 int offset = 0; /* Offset of value relative to the start obj */
1746 int abs_offset; /* Offset of value relative to start of wbuf */
1747 of_version_t ver;
1748""")
1749
1750 if not loxi_utils.type_is_scalar(m_type):
1751 out.write("""\
1752 int cur_len = 0; /* Current length of object data */
1753""")
1754 if a_type == "set":
1755 out.write("""\
1756 int new_len, delta; /* For set, need new length and delta */
1757""")
1758
1759 # For match, need octet string for set/get
1760 if m_type == "of_match_t":
1761 out.write("""\
1762 of_octets_t match_octets; /* Serialized string for match */
1763""")
1764
1765 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001766 LOCI_ASSERT(%(assert_str)s);
Rich Lanea06d0c32013-03-25 08:52:03 -07001767 ver = obj->version;
1768 wbuf = OF_OBJECT_TO_WBUF(obj);
Rich Lanee57f0432014-02-19 10:31:53 -08001769 LOCI_ASSERT(wbuf != NULL);
Rich Lanea06d0c32013-03-25 08:52:03 -07001770
1771 /* By version, determine offset and current length (where needed) */
1772 switch (ver) {
1773""" % dict(assert_str=obj_assert_check(cls)))
1774
1775 for first in sorted(ver_type_map):
1776 (prev_t, prev_o) = ver_type_map[first]
1777 prev_len = length_of(prev_t, first)
1778 prev = first
1779 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1780 break
1781
1782 for next in sorted(ver_type_map):
1783 if next == first:
1784 continue
1785
1786 (t, o) = ver_type_map[next]
1787 cur_len = length_of(t, next)
1788 if o == prev_o and cur_len == prev_len:
1789 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1790 continue
1791 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1792 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1793 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1794
1795 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1796 out.write("""\
1797 default:
Rich Lanee57f0432014-02-19 10:31:53 -08001798 LOCI_ASSERT(0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001799 }
1800
1801 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
Rich Lanee57f0432014-02-19 10:31:53 -08001802 LOCI_ASSERT(abs_offset >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001803""")
1804 if not loxi_utils.type_is_scalar(m_type):
Rich Lanee57f0432014-02-19 10:31:53 -08001805 out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001806
1807 # Now generate the common accessor code
1808 if a_type in ["get", "bind"]:
1809 gen_get_accessor_body(out, cls, m_type, m_name)
1810 else:
1811 gen_set_accessor_body(out, cls, m_type, m_name)
1812
1813 out.write("""
1814 OF_LENGTH_CHECK_ASSERT(obj);
1815
1816 return %s;
1817}
1818""" % accessor_return_success(a_type, m_type))
1819
1820def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1821 """
1822 For generating the bind call for OF sub-objects
1823 """
1824
1825 params = ",\n ".join(param_list(cls, m_name, "bind"))
1826 out.write("""
1827/**
1828 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1829 * member %(m_name)s
1830 * @param obj Pointer to an object of type %(cls)s.
1831 * @param %(m_name)s Pointer to the child object of type
1832 * %(m_type)s to be filled out.
1833 * \ingroup %(cls)s
1834 *
1835 * The parameter %(m_name)s is filled out to point to the same underlying
1836 * wire buffer as its parent.
1837 *
1838 */
1839""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1840
1841 ret_type = accessor_return_type("bind", m_type)
1842 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1843 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1844
1845def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
1846 """
1847 For generating the get call for non- OF sub-objects
1848 """
1849 params = ",\n ".join(param_list(cls, m_name, "get"))
1850 out.write("""
1851/**
1852 * Get %(m_name)s from an object of type %(cls)s.
1853 * @param obj Pointer to an object of type %(cls)s.
1854 * @param %(m_name)s Pointer to the child object of type
1855 * %(m_type)s to be filled out.
1856 *
1857 */
1858""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1859
1860 ret_type = accessor_return_type("get", m_type)
1861 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
1862 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
1863
Rich Lanece2e4642013-12-15 12:05:45 -08001864def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001865 for m_name in of_g.ordered_members[cls]:
1866 if m_name in of_g.skip_members:
1867 continue
1868 m_type = loxi_utils.member_base_type(cls, m_name)
1869 ver_type_map = field_ver_get(cls, m_name)
1870
1871 # Generate get/bind pending on member type
1872 # FIXME: Does this do the right thing for match?
1873 if loxi_utils.type_is_of_object(m_type):
1874 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
1875 gen_of_object_get(out, cls, m_name, m_type)
1876 else:
1877 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
1878
1879 # Now generate set accessor for all objects
1880 params = ",\n ".join(param_list(cls, m_name, "set"))
1881 out.write("""
1882/**
1883 * Set %(m_name)s in an object of type %(cls)s.
1884 * @param obj Pointer to an object of type %(cls)s.
1885""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1886 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1887 out.write("""\
1888 * @param %(m_name)s The value to write into the object
1889 */
1890""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1891 else:
1892 out.write("""\
1893 * @param %(m_name)s Pointer to the child of type %(m_type)s.
1894 *
1895 * If the child's wire buffer is the same as the parent's, then
1896 * nothing is done as the changes have already been registered in the
1897 * parent. Otherwise, the data in the child's wire buffer is inserted
1898 * into the parent's and the appropriate lengths are updated.
1899 */
1900""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1901 ret_type = accessor_return_type("set", m_type)
1902 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
1903 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
1904
Rich Lanea06d0c32013-03-25 08:52:03 -07001905################################################################
1906#
1907# New/Delete Function Definitions
1908#
1909################################################################
1910
Rich Lanea06d0c32013-03-25 08:52:03 -07001911################################################################
1912# Routines to generate the body of new/delete functions
1913################################################################
1914
1915def gen_init_fn_body(cls, out):
1916 """
1917 Generate function body for init function
1918 @param cls The class name for the function
1919 @param out The file to which to write
1920 """
1921 if cls in type_maps.inheritance_map:
1922 param = "obj_p"
1923 else:
1924 param = "obj"
1925
1926 out.write("""
1927/**
1928 * Initialize an object of type %(cls)s.
1929 *
1930 * @param obj Pointer to the object to initialize
1931 * @param version The wire version to use for the object
1932 * @param bytes How many bytes in the object
1933 * @param clean_wire Boolean: If true, clear the wire object control struct
1934 *
1935 * If bytes < 0, then the default fixed length is used for the object
1936 *
1937 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07001938 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07001939 *
1940 * If anything other than 0 is passed in for the buffer size, the underlying
1941 * wire buffer will have 'grow' called.
1942 */
1943
1944void
1945%(cls)s_init(%(cls)s_t *%(param)s,
1946 of_version_t version, int bytes, int clean_wire)
1947{
1948""" % dict(cls=cls, param=param))
1949
1950 # Use an extra pointer to deal with inheritance classes
1951 if cls in type_maps.inheritance_map:
1952 out.write("""\
1953 %s_header_t *obj;
1954
1955 obj = &obj_p->header; /* Need instantiable subclass */
1956""" % cls)
1957
1958 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001959 LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001960 if (clean_wire) {
1961 MEMSET(obj, 0, sizeof(*obj));
1962 }
1963 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07001964 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07001965 }
1966 obj->version = version;
1967 obj->length = bytes;
1968 obj->object_id = %(enum)s;
1969""" % dict(cls=cls, enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001970
1971 out.write("""
1972 /* Grow the wire buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -07001973 if (obj->wbuf != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001974 int tot_bytes;
1975
Rich Lanecdd542d2014-04-03 16:13:12 -07001976 tot_bytes = bytes + obj->obj_offset;
1977 of_wire_buffer_grow(obj->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -07001978 }
1979}
1980
1981""")
1982
1983## @fixme This should also be updated once there is a map from
1984# class instance to wire length/type accessors
1985def gen_wire_push_fn(cls, out):
1986 """
1987 Generate the calls to push values into the wire buffer
1988 """
1989 if type_maps.class_is_virtual(cls):
1990 print "Push fn gen called for virtual class " + cls
1991 return
1992
1993 out.write("""
1994/**
1995 * Helper function to push values into the wire buffer
1996 */
1997static inline int
1998%(cls)s_push_wire_values(%(cls)s_t *obj)
1999{
2000""" % dict(cls=cls))
2001
Rich Lanebdd8e292013-12-06 17:37:39 -08002002 import loxi_globals
2003 uclass = loxi_globals.unified.class_by_name(cls)
2004 if uclass and not uclass.virtual and uclass.has_type_members:
2005 out.write("""
2006 %(cls)s_push_wire_types(obj);
2007""" % dict(cls=cls))
2008
Rich Lanea06d0c32013-03-25 08:52:03 -07002009 if loxi_utils.class_is_message(cls):
2010 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002011 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002012 of_message_t msg;
2013
2014 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002015 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002016 }
2017""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002018
Rich Lanea06d0c32013-03-25 08:52:03 -07002019 else: # Not a message
2020 if loxi_utils.class_is_tlv16(cls):
2021 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002022 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002023 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002024""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07002025
Rich Lanea06d0c32013-03-25 08:52:03 -07002026 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2027 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07002028 of_object_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002029""")
2030
2031 if cls == "of_meter_stats":
2032 out.write("""
2033 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2034""" % dict(enum=enum_name(cls)))
2035
2036 out.write("""
2037 return OF_ERROR_NONE;
2038}
2039""")
2040
2041def gen_new_fn_body(cls, out):
2042 """
2043 Generate function body for new function
2044 @param cls The class name for the function
2045 @param out The file to which to write
2046 """
2047
2048 out.write("""
2049/**
2050 * \\defgroup %(cls)s %(cls)s
2051 */
2052""" % dict(cls=cls))
2053
2054 if not type_maps.class_is_virtual(cls):
2055 gen_wire_push_fn(cls, out)
2056
Rich Lane37911fd2014-04-01 22:11:22 -07002057 uclass = loxi_globals.unified.class_by_name(cls)
2058 is_fixed_length = uclass and uclass.is_fixed_length
2059 max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
2060
Rich Lanea06d0c32013-03-25 08:52:03 -07002061 out.write("""
2062/**
2063 * Create a new %(cls)s object
2064 *
2065 * @param version The wire version to use for the object
2066 * @return Pointer to the newly create object or NULL on error
2067 *
2068 * Initializes the new object with it's default fixed length associating
2069 * a new underlying wire buffer.
2070 *
2071 * Use new_from_message to bind an existing message to a message object,
2072 * or a _get function for non-message objects.
2073 *
2074 * \\ingroup %(cls)s
2075 */
2076
2077%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002078%(cls)s_new(of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -07002079{
2080 %(cls)s_t *obj;
2081 int bytes;
2082
Rich Lanef70be942013-07-18 13:33:14 -07002083 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002084
Rich Lane37911fd2014-04-01 22:11:22 -07002085 if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002086 return NULL;
2087 }
2088
2089 %(cls)s_init(obj, version, bytes, 0);
Rich Lane37911fd2014-04-01 22:11:22 -07002090""" % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
Rich Lanea06d0c32013-03-25 08:52:03 -07002091 if not type_maps.class_is_virtual(cls):
2092 out.write("""
2093 if (%(cls)s_push_wire_values(obj) < 0) {
2094 FREE(obj);
2095 return NULL;
2096 }
2097""" % dict(cls=cls))
2098
2099 match_offset = v3_match_offset_get(cls)
2100 if match_offset >= 0:
2101 # Init length field for match object
2102 out.write("""
2103 /* Initialize match TLV for 1.2 */
2104 /* FIXME: Check 1.3 below */
2105 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2106 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2107 }
2108""" % dict(match_offset=match_offset))
2109 out.write("""
2110 return obj;
2111}
Rich Lanea06d0c32013-03-25 08:52:03 -07002112""" % dict(cls=cls))
2113
2114
2115def gen_from_message_fn_body(cls, out):
2116 """
2117 Generate function body for from_message function
2118 @param cls The class name for the function
2119 @param out The file to which to write
2120 """
2121 out.write("""
2122/**
2123 * Create a new %(cls)s object and bind it to an existing message
2124 *
2125 * @param msg The message to bind the new object to
2126 * @return Pointer to the newly create object or NULL on error
2127 *
2128 * \ingroup %(cls)s
2129 */
2130
2131%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002132%(cls)s_new_from_message(of_message_t msg)
Rich Lanea06d0c32013-03-25 08:52:03 -07002133{
2134 %(cls)s_t *obj = NULL;
2135 of_version_t version;
2136 int length;
2137
2138 if (msg == NULL) return NULL;
2139
2140 version = of_message_version_get(msg);
2141 if (!OF_VERSION_OKAY(version)) return NULL;
2142
2143 length = of_message_length_get(msg);
2144
2145 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2146 return NULL;
2147 }
2148
2149 %(cls)s_init(obj, version, 0, 0);
2150
2151 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2152 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2153 FREE(obj);
2154 return NULL;
2155 }
2156 obj->length = length;
2157 obj->version = version;
2158
2159 return obj;
2160}
Rich Lanea06d0c32013-03-25 08:52:03 -07002161""" % dict(cls=cls))
2162
2163
2164################################################################
2165# Now the top level generator functions
2166################################################################
2167
2168def gen_new_function_declarations(out):
2169 """
2170 Gerenate the header file declarations for new operators for all classes
2171 @param out The file to which to write the decs
2172 """
2173
2174 out.write("""
2175/****************************************************************
2176 *
2177 * New operator declarations
2178 *
2179 * _new: Create a new object for writing; includes init
2180 * _new_from_message: Create a new instance of the object and bind the
2181 * message data to the object
2182 * _init: Initialize and optionally allocate buffer space for an
2183 * automatic instance
2184 *
2185 * _new and _from_message require a delete operation to be called
2186 * on the object.
2187 *
2188 ****************************************************************/
2189""")
Rich Lanea06d0c32013-03-25 08:52:03 -07002190
2191 for cls in of_g.standard_class_order:
2192 out.write("""
2193extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002194 %(cls)s_new(of_version_t version);
Rich Lanea06d0c32013-03-25 08:52:03 -07002195""" % dict(cls=cls))
2196 if loxi_utils.class_is_message(cls):
2197 out.write("""extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002198 %(cls)s_new_from_message(of_message_t msg);
Rich Lanea06d0c32013-03-25 08:52:03 -07002199""" % dict(cls=cls))
2200 out.write("""extern void %(cls)s_init(
2201 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2202""" % dict(cls=cls))
2203
2204 out.write("""
2205/****************************************************************
2206 *
2207 * Delete operator static inline definitions.
2208 * These are here for type checking purposes only
2209 *
2210 ****************************************************************/
2211""")
2212 for cls in of_g.standard_class_order:
2213# if cls in type_maps.inheritance_map:
2214# continue
2215 out.write("""
2216/**
2217 * Delete an object of type %(cls)s_t
2218 * @param obj An instance of type %(cls)s_t
2219 *
2220 * \ingroup %(cls)s
2221 */
2222static inline void
2223%(cls)s_delete(%(cls)s_t *obj) {
2224 of_object_delete((of_object_t *)(obj));
2225}
2226""" % dict(cls=cls))
2227
2228 out.write("""
2229typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
2230 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07002231extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07002232""")
2233
2234 out.write("""
2235/****************************************************************
2236 *
2237 * Function pointer initialization functions
2238 * These are part of the "coerce" type casting for objects
2239 *
2240 ****************************************************************/
2241""")
2242
Rich Laneb604e332013-12-15 13:23:51 -08002243def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002244 """
2245 Generate the new operator for all classes
2246
2247 @param out The file to which to write the functions
2248 """
2249
Rich Laneb604e332013-12-15 13:23:51 -08002250 gen_new_fn_body(cls, out)
2251 gen_init_fn_body(cls, out)
2252 if loxi_utils.class_is_message(cls):
2253 gen_from_message_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07002254
Rich Lanea06d0c32013-03-25 08:52:03 -07002255"""
2256Document generation functions
2257
2258The main reason this is here is to generate documentation per
2259accessor that indicates the versions that support the interface.
2260"""
2261
2262
2263def gen_accessor_doc(out, name):
2264 """
2265 Generate documentation for each accessor function that indicates
2266 the versions supporting the accessor.
2267 """
2268
2269 common_top_matter(out, name)
2270
2271 out.write("/* DOCUMENTATION ONLY */\n")
2272
2273 for cls in of_g.standard_class_order:
2274 if cls in type_maps.inheritance_map:
2275 pass # Check this
2276
2277 out.write("""
2278/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002279 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07002280 * accessors available in all versions unless noted otherwise
2281 *
2282""" % dict(cls=cls))
2283 if loxi_utils.class_is_list(cls):
2284 out.write("""\
2285 * @param first Function of type %(cls)s_first_f.
2286 * Setup a TBD class object to the first entry in the list
2287 * @param next Function of type %(cls)s_next_f.
2288 * Advance a TBD class object to the next entry in the list
2289 * @param append_bind Function of type %(cls)s_append_bind_f
2290 * Setup a TBD class object for append to the end of the current list
2291 * @param append Function of type @ref %(cls)s_append_f.
2292 * Copy an item to the end of a list
2293""" % dict(cls=cls))
2294
2295 for m_name in of_g.ordered_members[cls]:
2296 if m_name in of_g.skip_members:
2297 continue
2298 ver_type_map = field_ver_get(cls, m_name)
2299 (m_type, get_rv) = get_acc_rv(cls, m_name)
2300 if len(ver_type_map) == 3:
2301 # ver_string = "Available in all versions"
2302 ver_string = ""
2303 else:
2304 ver_string = "("
2305 for ver in sorted(ver_type_map):
2306 ver_string += " " + of_g.short_version_names[ver]
2307 ver_string += ")."
2308
2309 f_name = acc_name(cls, m_name)
2310 out.write("""\
2311 * @param %(m_name)s_get/set %(ver_string)s
2312 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
2313 * are of type %(f_name)s_get_f and _set_f.
2314 *
2315""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
2316
2317 out.write("""\
2318 */
2319typedef struct %(cls)s_s %(cls)s_t;
2320""" % dict(cls=cls))
2321
2322 out.write("#endif /* _LOCI_DOC_H_ */\n")