blob: 91bd07f2709a542c00a96007ab53c4671a3dc316 [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
309def base_h_external(out, filename):
310 """
311 Copy contents of external file to base header
312
313 The contents of the filename are copied literally into the
314 out file handler. This allows openflow common defines to
315 be entered into the LoxiGen code base. The content of this
316 code must depend only on standard C headers.
317 """
318 infile = open(filename, "r")
319 contents = infile.read()
320 out.write(contents)
321 infile.close()
322
323def match_h_gen(out, name):
324 """
325 Generate code for
326 @param out The file handle to write to
327 @param name The name of the file
328 """
329 c_match.match_h_top_matter(out, name)
330 c_match.gen_incompat_members(out)
331 c_match.gen_match_struct(out)
332 c_match.gen_match_comp(out)
333# c_match.gen_match_accessors(out)
334 out.write("\n#endif /* Match header file */\n")
335
336def top_h_gen(out, name):
337 """
338 Generate code for
339 @param out The file handle to write to
340 @param name The name of the file
341 """
342 external_h_top_matter(out, name)
343 out.write("""
344
345typedef enum loci_log_level {
346 LOCI_LOG_LEVEL_TRACE,
347 LOCI_LOG_LEVEL_VERBOSE,
348 LOCI_LOG_LEVEL_INFO,
349 LOCI_LOG_LEVEL_WARN,
350 LOCI_LOG_LEVEL_ERROR,
351 LOCI_LOG_LEVEL_MSG
352} loci_log_level_t;
353
354/**
355 * @brief Output a log message.
356 * @param level The log level.
357 * @param fname The function name.
358 * @param file The file name.
359 * @param line The line number.
360 * @param format The message format string.
361 */
362typedef int (*loci_logger_f)(loci_log_level_t level,
363 const char *fname, const char *file, int line,
364 const char *format, ...);
365
366/*
367 * This variable should be set by the user of the library to redirect logs to
368 * their log infrastructure. The default drops all logs.
369 */
370extern loci_logger_f loci_logger;
371
372/**
373 * Map a generic object to the underlying wire buffer
374 *
375 * Treat as private
376 */
377#define OF_OBJECT_TO_MESSAGE(obj) \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700378 ((of_message_t)(WBUF_BUF((obj)->wbuf)))
Rich Lanea06d0c32013-03-25 08:52:03 -0700379
380/**
381 * Macro for the fixed length part of an object
382 *
383 * @param obj The object whose extended length is being calculated
384 * @returns length in bytes of non-variable part of the object
385 */
386#define OF_OBJECT_FIXED_LENGTH(obj) \\
387 (of_object_fixed_len[(obj)->version][(obj)->object_id])
388
389/**
390 * Return the length of the object beyond its fixed length
391 *
392 * @param obj The object whose extended length is being calculated
393 * @returns length in bytes of non-variable part of the object
394 *
395 * Most variable length fields are alone at the end of a structure.
396 * Their length is a simple calculation, just the total length of
397 * the parent minus the length of the non-variable part of the
398 * parent's class type.
399 */
400
401#define OF_OBJECT_VARIABLE_LENGTH(obj) \\
402 ((obj)->length - OF_OBJECT_FIXED_LENGTH(obj))
403
404/* FIXME: Where do these go? */
405/* Low level maps btwn wire version + type and object ids */
406extern int of_message_is_stats_request(int type, int w_ver);
407extern int of_message_is_stats_reply(int type, int w_ver);
408extern int of_message_stats_reply_to_object_id(int stats_type, int w_ver);
409extern int of_message_stats_request_to_object_id(int stats_type, int w_ver);
410extern int of_message_type_to_object_id(int type, int w_ver);
411
412extern int of_wire_buffer_of_match_get(of_object_t *obj, int offset,
413 of_match_t *match);
414extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
415 of_match_t *match, int cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -0700416""")
417
418 # gen_base_types(out)
419
Rich Lanea06d0c32013-03-25 08:52:03 -0700420 gen_flow_add_setup_function_declarations(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700421 out.write("""
422/****************************************************************
423 *
424 * Declarations of maps between on-the-wire type values and LOCI identifiers
425 *
426 ****************************************************************/
Rich Lanec0e20ff2013-12-15 23:40:31 -0800427
428/**
429 * Generic experimenter type value. Applies to all except
430 * top level message: Action, instruction, error, stats, queue_props, oxm
431 */
432#define OF_EXPERIMENTER_TYPE 0xffff
433
434int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
435int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
436
437of_object_id_t of_action_to_object_id(int action, of_version_t version);
438of_object_id_t of_action_id_to_object_id(int action_id, of_version_t version);
439of_object_id_t of_instruction_to_object_id(int instruction, of_version_t version);
Jonathan Stout47832352014-03-03 12:48:23 -0500440of_object_id_t of_instruction_id_to_object_id(int instruction, of_version_t version);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800441of_object_id_t of_queue_prop_to_object_id(int queue_prop, of_version_t version);
442of_object_id_t of_table_feature_prop_to_object_id(int table_feature_prop, of_version_t version);
443of_object_id_t of_meter_band_to_object_id(int meter_band, of_version_t version);
444of_object_id_t of_hello_elem_to_object_id(int hello_elem, of_version_t version);
445of_object_id_t of_stats_reply_to_object_id(int stats_reply, of_version_t version);
446of_object_id_t of_stats_request_to_object_id(int stats_request, of_version_t version);
447of_object_id_t of_error_msg_to_object_id(uint16_t error_msg, of_version_t version);
448of_object_id_t of_flow_mod_to_object_id(int flow_mod, of_version_t version);
449of_object_id_t of_group_mod_to_object_id(int group_mod, of_version_t version);
450of_object_id_t of_oxm_to_object_id(uint32_t type_len, of_version_t version);
451of_object_id_t of_message_experimenter_to_object_id(of_message_t msg, of_version_t version);
452of_object_id_t of_message_to_object_id(of_message_t msg, int length);
Rich Lane713d9282013-12-30 15:21:35 -0800453of_object_id_t of_bsn_tlv_to_object_id(int tlv_type, of_version_t version);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800454
455int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
456
457extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];
458extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];
Rich Lanea06d0c32013-03-25 08:52:03 -0700459""")
Rich Lanea06d0c32013-03-25 08:52:03 -0700460 c_type_maps.gen_type_data_header(out)
461 c_match.gen_declarations(out)
462 # @fixme Move debug stuff to own fn
463 out.write("""
464/**
465 * Macro to check consistency of length for top level objects
466 *
467 * If the object has no parent then its length should match the
468 * underlying wire buffer's current bytes.
469 */
470#define OF_LENGTH_CHECK_ASSERT(obj) \\
Rich Lanee57f0432014-02-19 10:31:53 -0800471 LOCI_ASSERT(((obj)->parent != NULL) || \\
Rich Lanecdd542d2014-04-03 16:13:12 -0700472 ((obj)->wbuf == NULL) || \\
473 (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
Rich Lanea06d0c32013-03-25 08:52:03 -0700474
475#define OF_DEBUG_DUMP
476#if defined(OF_DEBUG_DUMP)
477extern void dump_match(of_match_t *match);
478#endif /* OF_DEBUG_DUMP */
479""")
480
481 out.write("\n#endif /* Top header file */\n")
482
483def match_c_gen(out, name):
484 """
485 Generate code for
486 @param out The file handle to write to
487 @param name The name of the file
488 """
489 c_match.match_c_top_matter(out, name)
490 c_match.gen_match_conversions(out)
491 c_match.gen_serialize(out)
492 c_match.gen_deserialize(out)
493
Rich Lanea06d0c32013-03-25 08:52:03 -0700494################################################################
495# Top Matter
496################################################################
497
498def common_top_matter(out, name):
499 loxi_utils.gen_c_copy_license(out)
500 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700501
Rich Lanea06d0c32013-03-25 08:52:03 -0700502/****************************************************************
503 * File: %s
504 *
505 * DO NOT EDIT
506 *
507 * This file is automatically generated
508 *
509 ****************************************************************/
510
511""" % name)
512
513 if name[-2:] == ".h":
514 out.write("""
515#if !defined(%(h)s)
516#define %(h)s
517
518""" % dict(h=h_file_to_define(name)))
519
520def base_h_content(out):
521 """
522 Generate base header file content
523
524 @param out The output file object
525 """
526
527 # @fixme Supported version should be generated based on input to LoxiGen
528
529 out.write("""
530/*
531 * Base OpenFlow definitions. These depend only on standard C headers
532 */
533#include <string.h>
534#include <stdint.h>
535
536/* g++ requires this to pick up PRI, etc.
537 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
538 */
539#if !defined(__STDC_FORMAT_MACROS)
540#define __STDC_FORMAT_MACROS
541#endif
542#include <inttypes.h>
543
544#include <stdlib.h>
545#include <assert.h>
546#include <loci/loci_idents.h>
547
548/**
549 * Macro to enable debugging for LOCI.
550 *
551 * This enables debug output to stdout.
552 */
553#define OF_DEBUG_ENABLE
554
555#if defined(OF_DEBUG_ENABLE)
556#include <stdio.h> /* Currently for debugging */
557#define FIXME(str) do { \\
558 fprintf(stderr, "%s\\n", str); \\
559 exit(1); \\
560 } while (0)
561#define debug printf
562#else
563#define FIXME(str)
564#define debug(str, ...)
565#endif /* OF_DEBUG_ENABLE */
566
567/**
568 * The type of a function used by the LOCI dump/show functions to
569 * output text. Essentially the same signature as fprintf. May
570 * be called many times per invocation of e.g. of_object_show().
571 */
572typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
573
574/**
575 * Check if a version is supported
576 */
577#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
578
579""")
580 gen_version_enum(out)
581 out.write("\n")
582
583 # for c_name in of_g.ofp_constants:
584 # val = str(of_g.ofp_constants[c_name])
585 # out.write("#define %s %s\n" % (c_name, val))
586 # out.write("\n")
587
588 out.write("""
589typedef enum of_error_codes_e {
590 OF_ERROR_NONE = 0,
591 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
592 OF_ERROR_PARAM = -2, /* Bad parameter */
593 OF_ERROR_VERSION = -3, /* Version not supported */
594 OF_ERROR_RANGE = -4, /* End of list indication */
595 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
596 OF_ERROR_PARSE = -6, /* Error in parsing data */
597 OF_ERROR_INIT = -7, /* Uninitialized data */
598 OF_ERROR_UNKNOWN = -8 /* Unknown error */
599} of_error_codes_t;
600
601#define OF_ERROR_STRINGS "none", \\
602 "resource", \\
603 "parameter", \\
604 "version", \\
605 "range", \\
606 "incompatible", \\
607 "parse", \\
608 "init", \\
609 "unknown"
610
Rich Laneb157b0f2013-03-27 13:55:28 -0700611extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700612
Rich Lanea8b54632014-02-19 11:17:47 -0800613#ifdef __GNUC__
614#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
615#else
616#define LOCI_NORETURN_ATTR
617#endif
618
619extern void loci_assert_fail(
620 const char *cond,
621 const char *file,
622 unsigned int line) LOCI_NORETURN_ATTR;
623
Rich Lane53757732013-02-23 17:00:10 -0800624#ifndef NDEBUG
Rich Lanea8b54632014-02-19 11:17:47 -0800625#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
Rich Lane53757732013-02-23 17:00:10 -0800626#else
Rich Lanee57f0432014-02-19 10:31:53 -0800627#define LOCI_ASSERT(val)
Rich Lane53757732013-02-23 17:00:10 -0800628#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700629
630/*
631 * Some LOCI object accessors can fail, and it's easy to forget to check.
632 * On certain compilers we can trigger a warning if the error code
633 * is ignored.
634 */
635#ifndef DISABLE_WARN_UNUSED_RESULT
636#ifdef __GNUC__
637#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
638#else
639#define WARN_UNUSED_RESULT
640#endif
641#else
642#define WARN_UNUSED_RESULT
643#endif
644
645typedef union of_generic_u of_generic_t;
646typedef struct of_object_s of_object_t;
647
648/* Define ipv4 address as uint32 */
649typedef uint32_t of_ipv4_t;
650
651/* Table ID is the OF standard uint8 */
652typedef uint8_t of_table_id_t;
653
654#define OF_MAC_ADDR_BYTES 6
655typedef struct of_mac_addr_s {
656 uint8_t addr[OF_MAC_ADDR_BYTES];
657} of_mac_addr_t;
658
659#define OF_IPV6_BYTES 16
660typedef struct of_ipv6_s {
661 uint8_t addr[OF_IPV6_BYTES];
662} of_ipv6_t;
663
664extern const of_mac_addr_t of_mac_addr_all_ones;
665extern const of_mac_addr_t of_mac_addr_all_zeros;
666
667extern const of_ipv6_t of_ipv6_all_ones;
668extern const of_ipv6_t of_ipv6_all_zeros;
669
670/**
671 * Generic zero and all-ones values of size 16 bytes.
672 *
673 * IPv6 is longest data type we worry about for comparisons
674 */
675#define of_all_zero_value of_ipv6_all_zeros
676#define of_all_ones_value of_ipv6_all_ones
677
678/**
679 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
680 */
681#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
682 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
683#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
684 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
685
686/* The octets object is a struct holding pointer and length */
687typedef struct of_octets_s {
688 uint8_t *data;
689 int bytes;
690} of_octets_t;
691
692/* Macro to convert an octet object to a pointer; currently trivial */
693#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
694#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
695#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
696#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
697
698/* Currently these are categorized as scalars */
699typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
700typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
701typedef char of_desc_str_t[OF_DESC_STR_LEN];
702typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
Rich Lanef8a3d002014-03-19 13:33:52 -0700703typedef char of_str64_t[64];
Rich Lanea06d0c32013-03-25 08:52:03 -0700704
Rich Lane3b2fd832013-09-24 13:44:08 -0700705typedef struct of_bitmap_128_s {
706 uint64_t hi;
707 uint64_t lo;
708} of_bitmap_128_t;
709
Rich Lanefab0c822013-12-30 11:46:48 -0800710typedef struct of_checksum_128_s {
711 uint64_t hi;
712 uint64_t lo;
713} of_checksum_128_t;
714
Rich Lanea06d0c32013-03-25 08:52:03 -0700715/* These are types which change across versions. */
716typedef uint32_t of_port_no_t;
717typedef uint16_t of_fm_cmd_t;
718typedef uint64_t of_wc_bmap_t;
719typedef uint64_t of_match_bmap_t;
720
721#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
722#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
723#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
724#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
725#define MALLOC(bytes) malloc(bytes)
726#define FREE(ptr) free(ptr)
727
728/** Try an operation and return on failure. */
729#define OF_TRY(op) do { \\
730 int _rv; \\
731 if ((_rv = (op)) < 0) { \\
732 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
733 return _rv; \\
734 } \\
735 } while (0)
736
737/* The extent of an OF match object is determined by its length field, but
738 * aligned to 8 bytes
739 */
740
741#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
742
Rich Lanedfcafae2014-03-06 16:56:49 -0800743#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
Rich Lanea06d0c32013-03-25 08:52:03 -0700744#define U16_NTOH(val) (val)
745#define U32_NTOH(val) (val)
746#define U64_NTOH(val) (val)
747#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
748#define U16_HTON(val) (val)
749#define U32_HTON(val) (val)
750#define U64_HTON(val) (val)
751#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
752#else /* Little Endian */
Rich Lane69e247e2014-03-05 10:27:22 -0800753#define U16_NTOH(val) (((val) >> 8) | (((val) & 0xff) << 8))
Rich Lanea06d0c32013-03-25 08:52:03 -0700754#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
755 (((val) & 0x00ff0000) >> 8) | \\
756 (((val) & 0x0000ff00) << 8) | \\
757 (((val) & 0x000000ff) << 24))
758#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
759 (((val) & 0x00ff000000000000LL) >> 40) | \\
760 (((val) & 0x0000ff0000000000LL) >> 24) | \\
761 (((val) & 0x000000ff00000000LL) >> 8) | \\
762 (((val) & 0x00000000ff000000LL) << 8) | \\
763 (((val) & 0x0000000000ff0000LL) << 24) | \\
764 (((val) & 0x000000000000ff00LL) << 40) | \\
765 (((val) & 0x00000000000000ffLL) << 56))
766#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
767#define U16_HTON(val) U16_NTOH(val)
768#define U32_HTON(val) U32_NTOH(val)
769#define U64_HTON(val) U64_NTOH(val)
770#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
771#endif
772
773/****************************************************************
774 *
775 * The following are internal definitions used by the automatically
776 * generated code. Users should not reference these definitions
777 * as they may change between versions of this code
778 *
779 ****************************************************************/
780
781#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
782 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
783#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
784#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
785 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
786
787#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
788 (FIXED_LEN + of_message_out_actions_len_get(obj))
789
790""")
791
792def external_h_top_matter(out, name):
793 """
794 Generate top matter for external header file
795
796 @param name The name of the output file
797 @param out The output file object
798 """
799 common_top_matter(out, name)
800 out.write("""
801#include <loci/loci_base.h>
802#include <loci/of_message.h>
803#include <loci/of_match.h>
804#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800805#include <loci/loci_classes.h>
Rich Lanedc46fe22014-04-03 15:10:38 -0700806#include <loci/loci_class_metadata.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700807
808/****************************************************************
809 *
810 * This file is divided into the following sections.
811 *
812 * A few object specific macros
813 * Class typedefs (no struct definitions)
814 * Per-data type accessor function typedefs
815 * Per-class new/delete function typedefs
816 * Per-class static delete functions
817 * Per-class, per-member accessor declarations
818 * Per-class structure definitions
819 * Generic union (inheritance) definitions
820 * Pointer set function declarations
821 * Some special case macros
822 *
823 ****************************************************************/
824""")
825
Rich Lanea06d0c32013-03-25 08:52:03 -0700826################################################################
827#
828################################################################
829
830def gen_version_enum(out):
831 """
832 Generate the enumerated type for versions in LoxiGen
833 @param out The file object to which to write the decs
834
835 This just uses the wire versions for now
836 """
837 out.write("""
838/**
839 * Enumeration of OpenFlow versions
840 *
841 * The wire protocol numbers are currently used for values of the corresponding
842 * version identifiers.
843 */
844typedef enum of_version_e {
845 OF_VERSION_UNKNOWN = 0,
846""")
847
848 is_first = True
849 max = 0
850 for v in of_g.wire_ver_map:
851 if is_first:
852 is_first = False
853 else:
854 out.write(",\n")
855 if v > max:
856 max = v
857 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
858
859 out.write("""
860} of_version_t;
861
862/**
863 * @brief Use this when declaring arrays indexed by wire version
864 */
865#define OF_VERSION_ARRAY_MAX %d
866""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700867
Rich Lanea06d0c32013-03-25 08:52:03 -0700868def gen_object_enum(out):
869 """
870 Generate the enumerated type for object identification in LoxiGen
871 @param out The file object to which to write the decs
872 """
873 out.write("""
874
875/**
876 * Enumeration of OpenFlow objects
877 *
878 * We enumerate the OpenFlow objects used internally. Note that some
879 * message types are determined both by an outer type (message type like
880 * stats_request) and an inner type (port stats). These are different
881 * messages in ofC.
882 *
883 * These values are for internal use only. They will change with
884 * different versions of ofC.
885 */
886
887typedef enum of_object_id_e {
888 /* Root object type */
889 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
890 OF_OBJECT = 0, /* Generic, untyped object */
891
892 /* OpenFlow message objects */
893""")
894 last = 0
895 msg_count = 0
896 for cls in of_g.ordered_messages:
897 out.write(" %s = %d,\n" % (enum_name(cls),
898 of_g.unified[cls]["object_id"]))
899 msg_count = of_g.unified[cls]["object_id"] + 1
900
901 out.write("\n /* Non-message objects */\n")
902 for cls in of_g.ordered_non_messages:
903 out.write(" %s = %d,\n" % (enum_name(cls),
904 of_g.unified[cls]["object_id"]))
905 last = of_g.unified[cls]["object_id"]
906 out.write("\n /* List objects */\n")
907 for cls in of_g.ordered_list_objects:
908 out.write(" %s = %d,\n" % (enum_name(cls),
909 of_g.unified[cls]["object_id"]))
910 last = of_g.unified[cls]["object_id"]
911
912 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
913 for cls in of_g.ordered_pseudo_objects:
914 out.write(" %s = %d,\n" % (enum_name(cls),
915 of_g.unified[cls]["object_id"]))
916 last = of_g.unified[cls]["object_id"]
917
918 out.write("""
919 OF_OBJECT_COUNT = %d
920} of_object_id_t;
921
Rich Laneb157b0f2013-03-27 13:55:28 -0700922extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700923
924#define OF_MESSAGE_OBJECT_COUNT %d
925""" % ((last + 1), msg_count))
926
927 # Generate object type range checking for inheritance classes
928
929 # @fixme These should be determined algorithmicly
930 out.write("""
931/*
932 * Macros to check if an object ID is within an inheritance class range
933 */
934""")
935 # Alphabetical order for 'last'
936 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
937 of_oxm="OF_OXM_VLAN_VID_MASKED",
938 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
939 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
940 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
941 # @FIXME add meter_band ?
942 )
943 for cls, last in last_ids.items():
944 out.write("""
945#define %(enum)s_FIRST_ID (%(enum)s + 1)
946#define %(enum)s_LAST_ID %(last)s
947#define %(enum)s_VALID_ID(id) \\
948 ((id) >= %(enum)s_FIRST_ID && \\
949 (id) <= %(enum)s_LAST_ID)
950""" % dict(enum=enum_name(cls), last=last))
951 out.write("""
952/**
953 * Function to check a wire ID
954 * @param object_id The ID to check
955 * @param base_object_id The inheritance parent, if applicable
956 * @returns boolean: If base_object_id is an inheritance class, check if
957 * object_id is valid as a subclass. Otherwise return 1.
958 *
959 * Note: Could check that object_id == base_object_id in the
960 * second case.
961 */
962static inline int
963of_wire_id_valid(int object_id, int base_object_id) {
964 switch (base_object_id) {
965 case OF_ACTION:
966 return OF_ACTION_VALID_ID(object_id);
967 case OF_OXM:
968 return OF_OXM_VALID_ID(object_id);
969 case OF_QUEUE_PROP:
970 return OF_QUEUE_PROP_VALID_ID(object_id);
971 case OF_TABLE_FEATURE_PROP:
972 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
973 case OF_INSTRUCTION:
974 return OF_INSTRUCTION_VALID_ID(object_id);
975 default:
976 break;
977 }
978 return 1;
979}
980""")
981
Rich Lanea06d0c32013-03-25 08:52:03 -0700982################################################################
983#
984# Internal Utility Functions
985#
986################################################################
987
988
989def acc_name(cls, m_name):
990 """
991 Generate the root name of an accessor function for typedef
992 @param cls The class name
993 @param m_name The member name
994 """
995 (m_type, get_rv) = get_acc_rv(cls, m_name)
996 return "%s_%s" % (cls, m_type)
997
998def get_acc_rv(cls, m_name):
999 """
1000 Determine the data type and return type for a get accessor.
1001
1002 The return type may be "void" or it may be the accessor type
1003 depending on the system configuration and on the data type.
1004
1005 @param cls The class name
1006 @param m_name The member name
1007 @return A pair (m_type, rv) where m_type is the unified type of the
1008 member and rv is the get_accessor return type
1009 """
1010 member = of_g.unified[cls]["union"][m_name]
1011 m_type = member["m_type"]
1012 rv = "int"
Rich Lanea06d0c32013-03-25 08:52:03 -07001013 if m_type[-2:] == "_t":
1014 m_type = m_type[:-2]
1015
1016 return (m_type, rv)
1017
1018def param_list(cls, m_name, a_type):
1019 """
1020 Generate the parameter list (no parens) for an a_type accessor
1021 @param cls The class name
1022 @param m_name The member name
1023 @param a_type One of "set" or "get" or TBD
1024 """
1025 member = of_g.unified[cls]["union"][m_name]
1026 m_type = member["m_type"]
1027 params = ["%s_t *obj" % cls]
1028 if a_type == "set":
1029 if loxi_utils.type_is_scalar(m_type):
1030 params.append("%s %s" % (m_type, m_name))
1031 else:
1032 params.append("%s *%s" % (m_type, m_name))
1033 elif a_type in ["get", "bind"]:
1034 params.append("%s *%s" % (m_type, m_name))
1035 else:
1036 debug("Class %s, name %s Bad param list a_type: %s" %
1037 (cls, m_name, a_type))
1038 sys.exit(1)
1039 return params
1040
1041def typed_function_base(cls, m_name):
1042 """
1043 Generate the core name for accessors based on the type
1044 @param cls The class name
1045 @param m_name The member name
1046 """
1047 (m_type, get_rv) = get_acc_rv(cls, m_name)
1048 return "%s_%s" % (cls, m_type)
1049
1050def member_function_base(cls, m_name):
1051 """
1052 Generate the core name for accessors based on the member name
1053 @param cls The class name
1054 @param m_name The member name
1055 """
1056 return "%s_%s" % (cls, m_name)
1057
1058def field_ver_get(cls, m_name):
1059 """
1060 Generate a dict, indexed by wire version, giving a pair (type, offset)
1061
1062 @param cls The class name
1063 @param m_name The name of the class member
1064
1065 If offset is not known for m_name, the type
1066 A dict is used for more convenient indexing.
1067 """
1068 result = {}
1069
1070 for ver in of_g.unified[cls]:
1071 if type(ver) == type(0): # It's a version
1072 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1073 ref_ver = of_g.unified[cls][ver]["use_version"]
1074 members = of_g.unified[cls][ref_ver]["members"]
1075 else:
1076 members = of_g.unified[cls][ver]["members"]
1077 idx = loxi_utils.member_to_index(m_name, members)
1078 if (idx < 0):
1079 continue # Member not in this version
1080 m_type = members[idx]["m_type"]
1081 offset = members[idx]["offset"]
1082
1083 # If m_type is mixed, get wire version type from global data
1084 if m_type in of_g.of_mixed_types and \
1085 ver in of_g.of_mixed_types[m_type]:
1086 m_type = of_g.of_mixed_types[m_type][ver]
1087
1088 # add version to result list
1089 result[ver] = (m_type, offset)
1090
1091 return result
1092
1093def v3_match_offset_get(cls):
1094 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001095 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001096 otherwise return -1
1097 """
1098 result = field_ver_get(cls, "match")
1099 if of_g.VERSION_1_2 in result:
1100 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1101 return result[of_g.VERSION_1_2][1]
1102 return -1
1103
1104################################################################
1105#
1106# OpenFlow Object Definitions
1107#
1108################################################################
1109
1110
1111def gen_of_object_defs(out):
1112 """
1113 Generate low level of_object core operations
1114 @param out The file for output, already open
1115 """
1116
1117def gen_generics(out):
1118 for (cls, subclasses) in type_maps.inheritance_map.items():
1119 out.write("""
1120/**
1121 * Inheritance super class for %(cls)s
1122 *
1123 * This class is the union of %(cls)s classes. You can refer
1124 * to it untyped by refering to the member 'header' whose structure
1125 * is common across all sub-classes.
1126 */
1127
1128union %(cls)s_u {
1129 %(cls)s_header_t header; /* Generic instance */
1130""" % dict(cls=cls))
1131 for subcls in sorted(subclasses):
1132 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1133 out.write("};\n")
1134
1135def gen_struct_typedefs(out):
1136 """
1137 Generate typedefs for all struct objects
1138 @param out The file for output, already open
1139 """
1140
1141 out.write("\n/* LOCI inheritance parent typedefs */\n")
1142 for cls in type_maps.inheritance_map:
1143 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1144 out.write("\n/* LOCI object typedefs */\n")
1145 for cls in of_g.standard_class_order:
1146 if cls in type_maps.inheritance_map:
1147 continue
Rich Lane85767872013-12-15 16:24:42 -08001148 template = "typedef of_object_t %(cls)s_t;\n"
1149 out.write(template % dict(cls=cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001150
1151 out.write("""
1152/****************************************************************
1153 *
1154 * Additional of_object defines
1155 * These are needed for some static inline ops, so we put them here.
1156 *
1157 ****************************************************************/
1158
1159/* Delete an OpenFlow object without reference to its type */
1160extern void of_object_delete(of_object_t *obj);
1161
1162""")
1163
Rich Lanea06d0c32013-03-25 08:52:03 -07001164def gen_flow_add_setup_function_declarations(out):
1165 """
1166 Add the declarations for functions that can be initialized
1167 by a flow add. These are defined external to LOXI.
1168 """
1169
1170 out.write("""
1171/****************************************************************
1172 * Functions for objects that can be initialized by a flow add message.
1173 * These are defined in a non-autogenerated file
1174 ****************************************************************/
1175
1176/**
1177 * @brief Set up a flow removed message from the original add
1178 * @param obj The flow removed message being updated
1179 * @param flow_add The flow_add message to use
1180 *
1181 * Initialize the following fields of obj to be identical
1182 * to what was originally on the wire from the flow_add object:
1183 * match
1184 * cookie
1185 * priority
1186 * idle_timeout
1187 * hard_timeout
1188 *
1189 */
1190
1191extern int
1192of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1193 of_flow_add_t *flow_add);
1194
1195
1196/**
1197 * @brief Set up the packet in match structure from the original add
1198 * @param obj The packet in message being updated
1199 * @param flow_add The flow_add message to use
1200 * @returns Indigo error code. Does not return a version error if
1201 * the version does not require initializing obj.
1202 *
1203 * Initialize the match member of obj to be identical to what was originally
1204 * on the wire from the flow_add object. If applicable, the table ID is also
1205 * initialized from the flow_add object.
1206 *
1207 * This API applies to 1.2 and later only.
1208 */
1209
1210extern int
1211of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1212 of_flow_add_t *flow_add);
1213
1214
1215/**
1216 * @brief Set up the flow stats entry from the original add
1217 * @param obj The packet in message being updated
1218 * @param flow_add The flow_add message to use
1219 * @param effects Optional actions or instructions; see below.
1220 *
1221 * Initialize the following fields of obj to be identical
1222 * to what was originally on the wire from the flow_add object:
1223 * match
1224 * actions/instructions (effects)
1225 * cookie
1226 * priority
1227 * idle_timeout
1228 * hard_timeout
1229 *
Andreas Wundsam53256162013-05-02 14:05:53 -07001230 * Note that the actions/instructions of a flow may be modified by a
Rich Lanea06d0c32013-03-25 08:52:03 -07001231 * subsequent flow modify message. To facilitate implementations,
1232 * the "effects" parameter is provided. If effects is NULL, the
1233 * actions/instructions are taken from the flow_add message.
1234 * Otherwise, effects is coerced to the proper type (actions or
1235 * instructions) and used to init obj.
1236 */
1237
1238extern int
1239of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1240 of_flow_add_t *flow_add,
1241 of_object_t *effects);
1242""")
1243
Rich Lanea06d0c32013-03-25 08:52:03 -07001244################################################################
1245#
1246# List accessor code generation
1247#
1248# Currently these all implement copy on read semantics
1249#
1250################################################################
1251
1252def init_call(e_type, obj, ver, length, cw):
1253 """
1254 Generate the init call given the strings for params
1255 """
1256 hdr = "" # If inheritance type, coerce to hdr object
1257 obj_name = obj
1258 if e_type in type_maps.inheritance_map:
1259 hdr = "_header"
1260 obj_name = "(%s_header_t *)" % e_type + obj
1261
1262 return """\
1263%(e_type)s%(hdr)s_init(%(obj_name)s,
1264 %(ver)s, %(length)s, %(cw)s)\
1265""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1266 length=length, cw=cw)
1267
1268def gen_list_first(out, cls, e_type):
1269 """
1270 Generate the body of a list_first operation
1271 @param cls The class name for which code is being generated
1272 @param e_type The element type of the list
1273 @param out The file to which to write
1274 """
1275 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1276 if e_type in type_maps.inheritance_map:
1277 len_str = "obj->header.length"
1278 else:
1279 len_str = "obj->length"
1280
1281 out.write("""
1282/**
1283 * Associate an iterator with a list
1284 * @param list The list to iterate over
1285 * @param obj The list entry iteration pointer
1286 * @return OF_ERROR_RANGE if the list is empty (end of list)
1287 *
1288 * The obj instance is completely initialized. The caller is responsible
1289 * for cleaning up any wire buffers associated with obj before this call
1290 */
1291
1292int
1293%(cls)s_first(%(cls)s_t *list,
1294 %(e_type)s_t *obj)
1295{
1296 int rv;
1297
1298 %(i_call)s;
1299 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1300 return rv;
1301 }
1302""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1303
1304 # Special case flow_stats_entry lists
1305
1306 out.write("""
1307 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1308 list->length);
1309 if (%(len_str)s == 0) {
1310 return OF_ERROR_PARSE;
1311 }
1312
1313 return rv;
1314}
1315""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1316
1317
1318def gen_bind(out, cls, m_name, m_type):
1319 """
1320 Generate the body of a bind function
1321 @param out The file to which to write
1322 @param cls The class name for which code is being generated
1323 @param m_name The name of the data member
1324 @param m_type The type of the data member
1325 """
1326
1327 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1328
1329 i_call = init_call(e_type, "child", "parent->version", "0", "1")
1330
1331 out.write("""
1332/**
1333 * Bind the child object to the parent object for read processing
1334 * @param parent The parent object
1335 * @param child The child object
1336 *
1337 * The child obj instance is completely initialized.
1338 */
1339
1340int
1341%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
1342 %(e_type)s_t *child)
1343{
1344 int rv;
1345
1346 %(i_call)s;
1347
1348 /* Derive offset and length of child in parent */
Andreas Wundsam53256162013-05-02 14:05:53 -07001349 OF_TRY(of_object_child_attach(parent, child,
Rich Lanea06d0c32013-03-25 08:52:03 -07001350 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1351 return rv;
1352 }
1353""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1354
1355 # Special case flow_stats_entry lists
1356
1357 out.write("""
1358 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1359 list->length);
1360 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1361 return OF_ERROR_PARSE;
1362 }
1363
1364 return rv;
1365}
1366""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1367
1368
1369def gen_list_next(out, cls, e_type):
1370 """
1371 Generate the body of a list_next operation
1372 @param cls The class name for which code is being generated
1373 @param e_type The element type of the list
1374 @param out The file to which to write
1375 """
1376
1377 if e_type in type_maps.inheritance_map:
1378 len_str = "obj->header.length"
1379 else:
1380 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001381
Rich Lanea06d0c32013-03-25 08:52:03 -07001382 out.write("""
1383/**
1384 * Advance an iterator to the next element in a list
1385 * @param list The list being iterated
1386 * @param obj The list entry iteration pointer
1387 * @return OF_ERROR_RANGE if already at the last entry on the list
1388 *
1389 */
1390
1391int
1392%(cls)s_next(%(cls)s_t *list,
1393 %(e_type)s_t *obj)
1394{
1395 int rv;
1396
1397 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1398 return rv;
1399 }
1400
1401 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1402 list->length);
1403
1404 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1405 return OF_ERROR_PARSE;
1406 }
1407
1408 return rv;
1409}
1410""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1411
1412def gen_list_append(out, cls, e_type):
1413 """
1414 Generate the body of a list append functions
1415 @param cls The class name for which code is being generated
1416 @param e_type The element type of the list
1417 @param out The file to which to write
1418 """
1419
1420 out.write("""
1421/**
1422 * Set up to append an object of type %(e_type)s to an %(cls)s.
1423 * @param list The list that is prepared for append
1424 * @param obj Pointer to object to hold data to append
1425 *
1426 * The obj instance is completely initialized. The caller is responsible
1427 * for cleaning up any wire buffers associated with obj before this call.
1428 *
1429 * See the generic documentation for of_list_append_bind.
1430 */
1431
1432int
1433%(cls)s_append_bind(%(cls)s_t *list,
1434 %(e_type)s_t *obj)
1435{
1436 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1437}
1438
1439/**
1440 * Append an item to a %(cls)s list.
1441 *
1442 * This copies data from item and leaves item untouched.
1443 *
1444 * See the generic documentation for of_list_append.
1445 */
1446
1447int
1448%(cls)s_append(%(cls)s_t *list,
1449 %(e_type)s_t *item)
1450{
1451 return of_list_append((of_object_t *)list, (of_object_t *)item);
1452}
1453
1454""" % dict(cls=cls, e_type=e_type))
1455
1456def gen_list_accessors(out, cls):
1457 e_type = loxi_utils.list_to_entry_type(cls)
1458 gen_list_first(out, cls, e_type)
1459 gen_list_next(out, cls, e_type)
1460 gen_list_append(out, cls, e_type)
1461
1462################################################################
1463#
1464# Accessor Functions
1465#
1466################################################################
1467
Andreas Wundsam53256162013-05-02 14:05:53 -07001468
Rich Lanea06d0c32013-03-25 08:52:03 -07001469def gen_accessor_declarations(out):
1470 """
1471 Generate the declaration of each version independent accessor
1472
1473 @param out The file to which to write the decs
1474 """
1475
1476 out.write("""
1477/****************************************************************
1478 *
1479 * Unified, per-member accessor function declarations
1480 *
1481 ****************************************************************/
1482""")
1483 for cls in of_g.standard_class_order:
1484 if cls in type_maps.inheritance_map:
1485 continue
1486 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1487 for m_name in of_g.ordered_members[cls]:
1488 if m_name in of_g.skip_members:
1489 continue
1490 m_type = loxi_utils.member_base_type(cls, m_name)
1491 base_name = "%s_%s" % (cls, m_name)
1492 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1493 get_ret_type = accessor_return_type("get", m_type)
1494 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1495 set_ret_type = accessor_return_type("set", m_type)
1496 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1497 bind_ret_type = accessor_return_type("bind", m_type)
1498
1499 if loxi_utils.type_is_of_object(m_type):
1500 # Generate bind accessors, but not get accessor
1501 out.write("""
1502extern %(set_ret_type)s %(base_name)s_set(
1503 %(sparams)s);
1504extern %(bind_ret_type)s %(base_name)s_bind(
1505 %(bparams)s);
1506extern %(m_type)s *%(cls)s_%(m_name)s_get(
1507 %(cls)s_t *obj);
1508""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1509 m_name=m_name, m_type=m_type, cls=cls,
1510 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1511 else:
1512 out.write("""
1513extern %(set_ret_type)s %(base_name)s_set(
1514 %(sparams)s);
1515extern %(get_ret_type)s %(base_name)s_get(
1516 %(gparams)s);
1517""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1518 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001519
Rich Lanea06d0c32013-03-25 08:52:03 -07001520 if loxi_utils.class_is_list(cls):
1521 e_type = loxi_utils.list_to_entry_type(cls)
1522 out.write("""
1523extern int %(cls)s_first(
1524 %(cls)s_t *list, %(e_type)s_t *obj);
1525extern int %(cls)s_next(
1526 %(cls)s_t *list, %(e_type)s_t *obj);
1527extern int %(cls)s_append_bind(
1528 %(cls)s_t *list, %(e_type)s_t *obj);
1529extern int %(cls)s_append(
1530 %(cls)s_t *list, %(e_type)s_t *obj);
1531
1532/**
1533 * Iteration macro for list of type %(cls)s
1534 * @param list Pointer to the list being iterated over of
1535 * type %(cls)s
1536 * @param elt Pointer to an element of type %(e_type)s
1537 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1538 */
1539#define %(u_cls)s_ITER(list, elt, rv) \\
1540 for ((rv) = %(cls)s_first((list), (elt)); \\
1541 (rv) == OF_ERROR_NONE; \\
1542 (rv) = %(cls)s_next((list), (elt)))
1543""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1544
1545
1546def wire_accessor(m_type, a_type):
1547 """
1548 Returns the name of the a_type accessor for low level wire buff offset
1549 @param m_type The member type
1550 @param a_type The accessor type (set or get)
1551 """
1552 # Strip off _t if present
1553 if m_type in of_g.of_base_types:
1554 m_type = of_g.of_base_types[m_type]["short_name"]
1555 if m_type in of_g.of_mixed_types:
1556 m_type = of_g.of_mixed_types[m_type]["short_name"]
1557 if m_type[-2:] == "_t":
1558 m_type = m_type[:-2]
1559 if m_type == "octets":
1560 m_type = "octets_data"
1561 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1562
Rich Lane713d9282013-12-30 15:21:35 -08001563def get_len_macro(cls, m_name, m_type, version):
Rich Lanea06d0c32013-03-25 08:52:03 -07001564 """
1565 Get the length macro for m_type in cls
1566 """
1567 if m_type.find("of_match") == 0:
1568 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1569 if m_type.find("of_list_oxm") == 0:
1570 return "wire_match_len(obj, 0) - 4"
1571 if loxi_utils.class_is_tlv16(m_type):
1572 return "_TLV16_LEN(obj, offset)"
1573 if cls == "of_packet_out" and m_type == "of_list_action_t":
1574 return "_PACKET_OUT_ACTION_LEN(obj)"
Rich Lane713d9282013-12-30 15:21:35 -08001575 if cls == "of_bsn_gentable_entry_add" and m_name == "key":
1576 return "of_object_u16_get(obj, 18)"
1577 if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
1578 return "of_object_u16_get(obj, 2)"
1579 if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
1580 return "of_object_u16_get(obj, 2)"
Rich Lanea06d0c32013-03-25 08:52:03 -07001581 # Default is everything to the end of the object
1582 return "_END_LEN(obj, offset)"
1583
1584def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1585 """
1586 Generate the sub-object offset and length calculations for accessors
1587 @param out File being written
1588 @param m_name Name of member
1589 @param version Wire version being processed
1590 @param a_type The accessor type (set or get)
1591 @param m_type The original member type
1592 @param offset The offset of the object or -1 if not fixed
1593 """
1594 # determine offset
1595 o_str = "%d" % offset # Default is fixed length
1596 if offset == -1:
1597 # There are currently 4 special cases for this
1598 # In general, get offset and length of predecessor
1599 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1600 pass
1601 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1602 pass
1603 elif (cls == "of_packet_in" and m_name == "data"):
1604 pass
1605 elif (cls == "of_packet_out" and m_name == "data"):
1606 pass
Rich Lane713d9282013-12-30 15:21:35 -08001607 elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
1608 pass
1609 elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
1610 pass
1611 elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
1612 pass
Rich Lanea06d0c32013-03-25 08:52:03 -07001613 else:
1614 debug("Error: Unknown member with offset == -1")
1615 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1616 sys.exit(1)
1617 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1618
1619 out.write("""\
1620 offset = %s;
1621""" % o_str);
1622
1623 # This could be moved to main body but for version check
1624 if not loxi_utils.type_is_scalar(m_type):
1625 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1626 m_type == "of_match_t":
Rich Lane713d9282013-12-30 15:21:35 -08001627 len_macro = get_len_macro(cls, m_name, m_type, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001628 else:
1629 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1630 out.write(" cur_len = %s;\n" % len_macro)
1631 out.write(" break;\n")
1632
1633def length_of(m_type, version):
1634 """
1635 Return the length of a type based on the version
1636 """
1637 if m_type in of_g.of_mixed_types:
1638 m_type = of_g.of_mixed_types[m_type][version]
1639 if m_type in of_g.of_base_types:
1640 return of_g.of_base_types[m_type]["bytes"]
1641 if (m_type[:-2], version) in of_g.base_length:
1642 return of_g.base_length[(m_type[:-2], version)]
1643 print "Unknown length request", m_type, version
1644 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001645
Rich Lanea06d0c32013-03-25 08:52:03 -07001646
1647def gen_get_accessor_body(out, cls, m_type, m_name):
1648 """
1649 Generate the common operations for a get accessor
1650 """
1651 if loxi_utils.type_is_scalar(m_type):
1652 ver = "" # See if version required for scalar update
1653 if m_type in of_g.of_mixed_types:
1654 ver = "ver, "
1655 out.write("""\
1656 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1657""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1658
1659 if m_type == "of_port_no_t":
1660 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1661 elif m_type == "of_octets_t":
1662 out.write("""\
Rich Lanee57f0432014-02-19 10:31:53 -08001663 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001664 %(m_name)s->bytes = cur_len;
1665 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1666""" % dict(m_name=m_name))
1667 elif m_type == "of_match_t":
1668 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001669 LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
Rich Lanea06d0c32013-03-25 08:52:03 -07001670 match_octets.bytes = cur_len;
1671 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
1672 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
1673""" % dict(m_name=m_name))
Rich Lane90020b42014-04-07 12:05:45 -07001674 elif m_type == "of_oxm_header_t":
1675 out.write("""
1676 /* Initialize child */
1677 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1678 /* Attach to parent */
1679 %(m_name)s->parent = (of_object_t *)obj;
1680 %(m_name)s->wbuf = obj->wbuf;
1681 %(m_name)s->obj_offset = abs_offset;
1682 %(m_name)s->length = cur_len;
1683 of_object_wire_init(%(m_name)s, OF_OXM, 0);
1684""" % dict(m_type=m_type[:-2], m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001685 else:
1686 out.write("""
1687 /* Initialize child */
1688 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1689 /* Attach to parent */
1690 %(m_name)s->parent = (of_object_t *)obj;
Rich Lanecdd542d2014-04-03 16:13:12 -07001691 %(m_name)s->wbuf = obj->wbuf;
1692 %(m_name)s->obj_offset = abs_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -07001693 %(m_name)s->length = cur_len;
1694""" % dict(m_type=m_type[:-2], m_name=m_name))
1695
1696
1697def gen_set_accessor_body(out, cls, m_type, m_name):
1698 """
1699 Generate the contents of a set accessor
1700 """
1701 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1702 ver = "" # See if version required for scalar update
1703 if m_type in of_g.of_mixed_types:
1704 ver = "ver, "
1705 cur_len = "" # See if version required for scalar update
1706 if m_type == "of_octets_t":
1707 cur_len = ", cur_len"
1708 out.write("""\
1709 new_len = %(m_name)s->bytes;
1710 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1711""" % dict(m_name=m_name))
1712 out.write("""\
1713 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1714""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1715 m_name=m_name))
1716
1717 elif m_type == "of_match_t":
1718 out.write("""
1719 /* Match object */
1720 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1721 new_len = match_octets.bytes;
1722 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1723 match_octets.data, new_len);
1724 /* Free match serialized octets */
1725 FREE(match_octets.data);
1726""" % dict(m_name=m_name))
1727
1728 else: # Other object type
1729 out.write("\n /* LOCI object type */")
1730 # Need to special case OXM list
1731 out.write("""
1732 new_len = %(m_name)s->length;
1733 /* If underlying buffer already shared; nothing to do */
Rich Lanecdd542d2014-04-03 16:13:12 -07001734 if (obj->wbuf == %(m_name)s->wbuf) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001735 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1736 /* Verify that the offsets are correct */
Rich Lanee57f0432014-02-19 10:31:53 -08001737 LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1738 /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
Rich Lanea06d0c32013-03-25 08:52:03 -07001739 return %(ret_success)s;
1740 }
1741
1742 /* Otherwise, replace existing object in data buffer */
1743 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1744 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1745""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1746
1747 if not loxi_utils.type_is_scalar(m_type):
1748 if cls == "of_packet_out" and m_type == "of_list_action_t":
1749 out.write("""
1750 /* Special case for setting action lengths */
1751 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1752""" % dict(m_name=m_name))
Rich Lane713d9282013-12-30 15:21:35 -08001753 elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
1754 out.write("""
1755 /* Special case for setting key length */
1756 of_object_u16_set(obj, 18, %(m_name)s->length);
1757""" % dict(m_name=m_name))
1758 elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
1759 out.write("""
1760 /* Special case for setting key length */
1761 of_object_u16_set(obj, 2, %(m_name)s->length);
1762""" % dict(m_name=m_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001763 elif m_type not in ["of_match_t", "of_octets_t"]:
1764 out.write("""
1765 /* @fixme Shouldn't this precede copying value's data to buffer? */
Rich Lanedc46fe22014-04-03 15:10:38 -07001766 of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001767""" % dict(m_name=m_name))
1768 out.write("""
1769 /* Not scalar, update lengths if needed */
1770 delta = new_len - cur_len;
1771 if (delta != 0) {
1772 /* Update parent(s) */
1773 of_object_parent_length_update((of_object_t *)obj, delta);
1774 }
1775""")
1776
1777def obj_assert_check(cls):
1778 """
1779 The body of the assert check for an accessor
1780 We allow all versions of add/delete/modify to use the same accessors
1781 """
1782 if cls in ["of_flow_modify", "of_flow_modify_strict",
1783 "of_flow_delete", "of_flow_delete_strict",
1784 "of_flow_add"]:
1785 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1786 else:
1787 return "obj->object_id == %s" % cls.upper()
1788
1789def gen_of_object_get(out, cls, m_name, m_type):
1790 sub_cls = m_type[:-2]
1791 out.write("""
1792/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001793 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001794 * a %(cls)s instance.
1795 *
1796 * @param obj Pointer to the source of type %(cls)s_t
1797 * @returns A pointer to a new instance of type %(m_type)s whose contents
1798 * match that of %(m_name)s from source
1799 * @returns NULL if an error occurs
1800 */
1801%(m_type)s *
1802%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1803 %(m_type)s _%(m_name)s;
1804 %(m_type)s *_%(m_name)s_ptr;
1805
1806 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1807 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1808 return _%(m_name)s_ptr;
1809}
1810""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1811
1812def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1813 """
1814 Generate the body of a set or get accessor function
1815
1816 @param out The file to which to write the decs
1817 @param cls The class name
1818 @param m_name The member name
1819 @param ver_type_map Maps (type, offset) pairs to a list of versions
1820 @param a_type The accessor type, set or get
1821 @param m_type The original member type
1822
1823 The type values in ver_type_map are now ignored as we've pushed down
1824 the type munging to the lower level.
1825
1826 This is unified because the version switch case processing is the
1827 same for both set and get
1828 """
1829 out.write("""{
1830 of_wire_buffer_t *wbuf;
1831 int offset = 0; /* Offset of value relative to the start obj */
1832 int abs_offset; /* Offset of value relative to start of wbuf */
1833 of_version_t ver;
1834""")
1835
1836 if not loxi_utils.type_is_scalar(m_type):
1837 out.write("""\
1838 int cur_len = 0; /* Current length of object data */
1839""")
1840 if a_type == "set":
1841 out.write("""\
1842 int new_len, delta; /* For set, need new length and delta */
1843""")
1844
1845 # For match, need octet string for set/get
1846 if m_type == "of_match_t":
1847 out.write("""\
1848 of_octets_t match_octets; /* Serialized string for match */
1849""")
1850
1851 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08001852 LOCI_ASSERT(%(assert_str)s);
Rich Lanea06d0c32013-03-25 08:52:03 -07001853 ver = obj->version;
1854 wbuf = OF_OBJECT_TO_WBUF(obj);
Rich Lanee57f0432014-02-19 10:31:53 -08001855 LOCI_ASSERT(wbuf != NULL);
Rich Lanea06d0c32013-03-25 08:52:03 -07001856
1857 /* By version, determine offset and current length (where needed) */
1858 switch (ver) {
1859""" % dict(assert_str=obj_assert_check(cls)))
1860
1861 for first in sorted(ver_type_map):
1862 (prev_t, prev_o) = ver_type_map[first]
1863 prev_len = length_of(prev_t, first)
1864 prev = first
1865 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1866 break
1867
1868 for next in sorted(ver_type_map):
1869 if next == first:
1870 continue
1871
1872 (t, o) = ver_type_map[next]
1873 cur_len = length_of(t, next)
1874 if o == prev_o and cur_len == prev_len:
1875 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1876 continue
1877 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1878 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1879 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1880
1881 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1882 out.write("""\
1883 default:
Rich Lanee57f0432014-02-19 10:31:53 -08001884 LOCI_ASSERT(0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001885 }
1886
1887 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
Rich Lanee57f0432014-02-19 10:31:53 -08001888 LOCI_ASSERT(abs_offset >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07001889""")
1890 if not loxi_utils.type_is_scalar(m_type):
Rich Lanee57f0432014-02-19 10:31:53 -08001891 out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001892
1893 # Now generate the common accessor code
1894 if a_type in ["get", "bind"]:
1895 gen_get_accessor_body(out, cls, m_type, m_name)
1896 else:
1897 gen_set_accessor_body(out, cls, m_type, m_name)
1898
1899 out.write("""
1900 OF_LENGTH_CHECK_ASSERT(obj);
1901
1902 return %s;
1903}
1904""" % accessor_return_success(a_type, m_type))
1905
1906def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1907 """
1908 For generating the bind call for OF sub-objects
1909 """
1910
1911 params = ",\n ".join(param_list(cls, m_name, "bind"))
1912 out.write("""
1913/**
1914 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1915 * member %(m_name)s
1916 * @param obj Pointer to an object of type %(cls)s.
1917 * @param %(m_name)s Pointer to the child object of type
1918 * %(m_type)s to be filled out.
1919 * \ingroup %(cls)s
1920 *
1921 * The parameter %(m_name)s is filled out to point to the same underlying
1922 * wire buffer as its parent.
1923 *
1924 */
1925""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1926
1927 ret_type = accessor_return_type("bind", m_type)
1928 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1929 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1930
1931def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
1932 """
1933 For generating the get call for non- OF sub-objects
1934 """
1935 params = ",\n ".join(param_list(cls, m_name, "get"))
1936 out.write("""
1937/**
1938 * Get %(m_name)s from an object of type %(cls)s.
1939 * @param obj Pointer to an object of type %(cls)s.
1940 * @param %(m_name)s Pointer to the child object of type
1941 * %(m_type)s to be filled out.
1942 *
1943 */
1944""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1945
1946 ret_type = accessor_return_type("get", m_type)
1947 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
1948 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
1949
Rich Lanece2e4642013-12-15 12:05:45 -08001950def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001951 for m_name in of_g.ordered_members[cls]:
1952 if m_name in of_g.skip_members:
1953 continue
1954 m_type = loxi_utils.member_base_type(cls, m_name)
1955 ver_type_map = field_ver_get(cls, m_name)
1956
1957 # Generate get/bind pending on member type
1958 # FIXME: Does this do the right thing for match?
1959 if loxi_utils.type_is_of_object(m_type):
1960 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
1961 gen_of_object_get(out, cls, m_name, m_type)
1962 else:
1963 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
1964
1965 # Now generate set accessor for all objects
1966 params = ",\n ".join(param_list(cls, m_name, "set"))
1967 out.write("""
1968/**
1969 * Set %(m_name)s in an object of type %(cls)s.
1970 * @param obj Pointer to an object of type %(cls)s.
1971""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1972 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1973 out.write("""\
1974 * @param %(m_name)s The value to write into the object
1975 */
1976""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1977 else:
1978 out.write("""\
1979 * @param %(m_name)s Pointer to the child of type %(m_type)s.
1980 *
1981 * If the child's wire buffer is the same as the parent's, then
1982 * nothing is done as the changes have already been registered in the
1983 * parent. Otherwise, the data in the child's wire buffer is inserted
1984 * into the parent's and the appropriate lengths are updated.
1985 */
1986""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1987 ret_type = accessor_return_type("set", m_type)
1988 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
1989 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
1990
Rich Lanea06d0c32013-03-25 08:52:03 -07001991################################################################
1992#
1993# New/Delete Function Definitions
1994#
1995################################################################
1996
1997
1998################################################################
1999# First, some utility functions for new/delete
2000################################################################
2001
2002def del_function_proto(cls):
2003 """
2004 Return the prototype for the delete operator for the given class
2005 @param cls The class name
2006 """
2007 fn = "void\n"
2008 return fn
2009
2010
Rich Lanea06d0c32013-03-25 08:52:03 -07002011################################################################
2012# Routines to generate the body of new/delete functions
2013################################################################
2014
2015def gen_init_fn_body(cls, out):
2016 """
2017 Generate function body for init function
2018 @param cls The class name for the function
2019 @param out The file to which to write
2020 """
2021 if cls in type_maps.inheritance_map:
2022 param = "obj_p"
2023 else:
2024 param = "obj"
2025
2026 out.write("""
2027/**
2028 * Initialize an object of type %(cls)s.
2029 *
2030 * @param obj Pointer to the object to initialize
2031 * @param version The wire version to use for the object
2032 * @param bytes How many bytes in the object
2033 * @param clean_wire Boolean: If true, clear the wire object control struct
2034 *
2035 * If bytes < 0, then the default fixed length is used for the object
2036 *
2037 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07002038 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07002039 *
2040 * If anything other than 0 is passed in for the buffer size, the underlying
2041 * wire buffer will have 'grow' called.
2042 */
2043
2044void
2045%(cls)s_init(%(cls)s_t *%(param)s,
2046 of_version_t version, int bytes, int clean_wire)
2047{
2048""" % dict(cls=cls, param=param))
2049
2050 # Use an extra pointer to deal with inheritance classes
2051 if cls in type_maps.inheritance_map:
2052 out.write("""\
2053 %s_header_t *obj;
2054
2055 obj = &obj_p->header; /* Need instantiable subclass */
2056""" % cls)
2057
2058 out.write("""
Rich Lanee57f0432014-02-19 10:31:53 -08002059 LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
Rich Lanea06d0c32013-03-25 08:52:03 -07002060 if (clean_wire) {
2061 MEMSET(obj, 0, sizeof(*obj));
2062 }
2063 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07002064 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002065 }
2066 obj->version = version;
2067 obj->length = bytes;
2068 obj->object_id = %(enum)s;
2069""" % dict(cls=cls, enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07002070
2071 out.write("""
2072 /* Grow the wire buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -07002073 if (obj->wbuf != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002074 int tot_bytes;
2075
Rich Lanecdd542d2014-04-03 16:13:12 -07002076 tot_bytes = bytes + obj->obj_offset;
2077 of_wire_buffer_grow(obj->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -07002078 }
2079}
2080
2081""")
2082
2083## @fixme This should also be updated once there is a map from
2084# class instance to wire length/type accessors
2085def gen_wire_push_fn(cls, out):
2086 """
2087 Generate the calls to push values into the wire buffer
2088 """
2089 if type_maps.class_is_virtual(cls):
2090 print "Push fn gen called for virtual class " + cls
2091 return
2092
2093 out.write("""
2094/**
2095 * Helper function to push values into the wire buffer
2096 */
2097static inline int
2098%(cls)s_push_wire_values(%(cls)s_t *obj)
2099{
2100""" % dict(cls=cls))
2101
Rich Lanebdd8e292013-12-06 17:37:39 -08002102 import loxi_globals
2103 uclass = loxi_globals.unified.class_by_name(cls)
2104 if uclass and not uclass.virtual and uclass.has_type_members:
2105 out.write("""
2106 %(cls)s_push_wire_types(obj);
2107""" % dict(cls=cls))
2108
Rich Lanea06d0c32013-03-25 08:52:03 -07002109 if loxi_utils.class_is_message(cls):
2110 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002111 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002112 of_message_t msg;
2113
2114 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002115 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002116 }
2117""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002118
Rich Lanea06d0c32013-03-25 08:52:03 -07002119 else: # Not a message
2120 if loxi_utils.class_is_tlv16(cls):
2121 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002122 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002123 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002124""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07002125
Rich Lanea06d0c32013-03-25 08:52:03 -07002126 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2127 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07002128 of_object_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002129""")
2130
2131 if cls == "of_meter_stats":
2132 out.write("""
2133 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2134""" % dict(enum=enum_name(cls)))
2135
2136 out.write("""
2137 return OF_ERROR_NONE;
2138}
2139""")
2140
2141def gen_new_fn_body(cls, out):
2142 """
2143 Generate function body for new function
2144 @param cls The class name for the function
2145 @param out The file to which to write
2146 """
2147
2148 out.write("""
2149/**
2150 * \\defgroup %(cls)s %(cls)s
2151 */
2152""" % dict(cls=cls))
2153
2154 if not type_maps.class_is_virtual(cls):
2155 gen_wire_push_fn(cls, out)
2156
Rich Lane37911fd2014-04-01 22:11:22 -07002157 uclass = loxi_globals.unified.class_by_name(cls)
2158 is_fixed_length = uclass and uclass.is_fixed_length
2159 max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
2160
Rich Lanea06d0c32013-03-25 08:52:03 -07002161 out.write("""
2162/**
2163 * Create a new %(cls)s object
2164 *
2165 * @param version The wire version to use for the object
2166 * @return Pointer to the newly create object or NULL on error
2167 *
2168 * Initializes the new object with it's default fixed length associating
2169 * a new underlying wire buffer.
2170 *
2171 * Use new_from_message to bind an existing message to a message object,
2172 * or a _get function for non-message objects.
2173 *
2174 * \\ingroup %(cls)s
2175 */
2176
2177%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002178%(cls)s_new(of_version_t version)
Rich Lanea06d0c32013-03-25 08:52:03 -07002179{
2180 %(cls)s_t *obj;
2181 int bytes;
2182
Rich Lanef70be942013-07-18 13:33:14 -07002183 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002184
Rich Lane37911fd2014-04-01 22:11:22 -07002185 if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002186 return NULL;
2187 }
2188
2189 %(cls)s_init(obj, version, bytes, 0);
Rich Lane37911fd2014-04-01 22:11:22 -07002190""" % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
Rich Lanea06d0c32013-03-25 08:52:03 -07002191 if not type_maps.class_is_virtual(cls):
2192 out.write("""
2193 if (%(cls)s_push_wire_values(obj) < 0) {
2194 FREE(obj);
2195 return NULL;
2196 }
2197""" % dict(cls=cls))
2198
2199 match_offset = v3_match_offset_get(cls)
2200 if match_offset >= 0:
2201 # Init length field for match object
2202 out.write("""
2203 /* Initialize match TLV for 1.2 */
2204 /* FIXME: Check 1.3 below */
2205 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2206 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2207 }
2208""" % dict(match_offset=match_offset))
2209 out.write("""
2210 return obj;
2211}
Rich Lanea06d0c32013-03-25 08:52:03 -07002212""" % dict(cls=cls))
2213
2214
2215def gen_from_message_fn_body(cls, out):
2216 """
2217 Generate function body for from_message function
2218 @param cls The class name for the function
2219 @param out The file to which to write
2220 """
2221 out.write("""
2222/**
2223 * Create a new %(cls)s object and bind it to an existing message
2224 *
2225 * @param msg The message to bind the new object to
2226 * @return Pointer to the newly create object or NULL on error
2227 *
2228 * \ingroup %(cls)s
2229 */
2230
2231%(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002232%(cls)s_new_from_message(of_message_t msg)
Rich Lanea06d0c32013-03-25 08:52:03 -07002233{
2234 %(cls)s_t *obj = NULL;
2235 of_version_t version;
2236 int length;
2237
2238 if (msg == NULL) return NULL;
2239
2240 version = of_message_version_get(msg);
2241 if (!OF_VERSION_OKAY(version)) return NULL;
2242
2243 length = of_message_length_get(msg);
2244
2245 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2246 return NULL;
2247 }
2248
2249 %(cls)s_init(obj, version, 0, 0);
2250
2251 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2252 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2253 FREE(obj);
2254 return NULL;
2255 }
2256 obj->length = length;
2257 obj->version = version;
2258
2259 return obj;
2260}
Rich Lanea06d0c32013-03-25 08:52:03 -07002261""" % dict(cls=cls))
2262
2263
2264################################################################
2265# Now the top level generator functions
2266################################################################
2267
2268def gen_new_function_declarations(out):
2269 """
2270 Gerenate the header file declarations for new operators for all classes
2271 @param out The file to which to write the decs
2272 """
2273
2274 out.write("""
2275/****************************************************************
2276 *
2277 * New operator declarations
2278 *
2279 * _new: Create a new object for writing; includes init
2280 * _new_from_message: Create a new instance of the object and bind the
2281 * message data to the object
2282 * _init: Initialize and optionally allocate buffer space for an
2283 * automatic instance
2284 *
2285 * _new and _from_message require a delete operation to be called
2286 * on the object.
2287 *
2288 ****************************************************************/
2289""")
Rich Lanea06d0c32013-03-25 08:52:03 -07002290
2291 for cls in of_g.standard_class_order:
2292 out.write("""
2293extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002294 %(cls)s_new(of_version_t version);
Rich Lanea06d0c32013-03-25 08:52:03 -07002295""" % dict(cls=cls))
2296 if loxi_utils.class_is_message(cls):
2297 out.write("""extern %(cls)s_t *
Rich Lanecd6ef152013-12-15 16:42:18 -08002298 %(cls)s_new_from_message(of_message_t msg);
Rich Lanea06d0c32013-03-25 08:52:03 -07002299""" % dict(cls=cls))
2300 out.write("""extern void %(cls)s_init(
2301 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2302""" % dict(cls=cls))
2303
2304 out.write("""
2305/****************************************************************
2306 *
2307 * Delete operator static inline definitions.
2308 * These are here for type checking purposes only
2309 *
2310 ****************************************************************/
2311""")
2312 for cls in of_g.standard_class_order:
2313# if cls in type_maps.inheritance_map:
2314# continue
2315 out.write("""
2316/**
2317 * Delete an object of type %(cls)s_t
2318 * @param obj An instance of type %(cls)s_t
2319 *
2320 * \ingroup %(cls)s
2321 */
2322static inline void
2323%(cls)s_delete(%(cls)s_t *obj) {
2324 of_object_delete((of_object_t *)(obj));
2325}
2326""" % dict(cls=cls))
2327
2328 out.write("""
2329typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
2330 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07002331extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07002332""")
2333
2334 out.write("""
2335/****************************************************************
2336 *
2337 * Function pointer initialization functions
2338 * These are part of the "coerce" type casting for objects
2339 *
2340 ****************************************************************/
2341""")
2342
Rich Laneb604e332013-12-15 13:23:51 -08002343def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002344 """
2345 Generate the new operator for all classes
2346
2347 @param out The file to which to write the functions
2348 """
2349
Rich Laneb604e332013-12-15 13:23:51 -08002350 gen_new_fn_body(cls, out)
2351 gen_init_fn_body(cls, out)
2352 if loxi_utils.class_is_message(cls):
2353 gen_from_message_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07002354
Rich Lanea06d0c32013-03-25 08:52:03 -07002355"""
2356Document generation functions
2357
2358The main reason this is here is to generate documentation per
2359accessor that indicates the versions that support the interface.
2360"""
2361
2362
2363def gen_accessor_doc(out, name):
2364 """
2365 Generate documentation for each accessor function that indicates
2366 the versions supporting the accessor.
2367 """
2368
2369 common_top_matter(out, name)
2370
2371 out.write("/* DOCUMENTATION ONLY */\n")
2372
2373 for cls in of_g.standard_class_order:
2374 if cls in type_maps.inheritance_map:
2375 pass # Check this
2376
2377 out.write("""
2378/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002379 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07002380 * accessors available in all versions unless noted otherwise
2381 *
2382""" % dict(cls=cls))
2383 if loxi_utils.class_is_list(cls):
2384 out.write("""\
2385 * @param first Function of type %(cls)s_first_f.
2386 * Setup a TBD class object to the first entry in the list
2387 * @param next Function of type %(cls)s_next_f.
2388 * Advance a TBD class object to the next entry in the list
2389 * @param append_bind Function of type %(cls)s_append_bind_f
2390 * Setup a TBD class object for append to the end of the current list
2391 * @param append Function of type @ref %(cls)s_append_f.
2392 * Copy an item to the end of a list
2393""" % dict(cls=cls))
2394
2395 for m_name in of_g.ordered_members[cls]:
2396 if m_name in of_g.skip_members:
2397 continue
2398 ver_type_map = field_ver_get(cls, m_name)
2399 (m_type, get_rv) = get_acc_rv(cls, m_name)
2400 if len(ver_type_map) == 3:
2401 # ver_string = "Available in all versions"
2402 ver_string = ""
2403 else:
2404 ver_string = "("
2405 for ver in sorted(ver_type_map):
2406 ver_string += " " + of_g.short_version_names[ver]
2407 ver_string += ")."
2408
2409 f_name = acc_name(cls, m_name)
2410 out.write("""\
2411 * @param %(m_name)s_get/set %(ver_string)s
2412 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
2413 * are of type %(f_name)s_get_f and _set_f.
2414 *
2415""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
2416
2417 out.write("""\
2418 */
2419typedef struct %(cls)s_s %(cls)s_t;
2420""" % dict(cls=cls))
2421
2422 out.write("#endif /* _LOCI_DOC_H_ */\n")
2423
2424################################################################
2425#
2426# For fun, here are some unified, traditional C structure representation
2427#
2428################################################################
2429
2430def gen_cof_to_wire(out):
2431 pass
2432
2433def gen_wire_to_cof(out):
2434 pass
2435
2436def gen_cof_instance(out, cls):
2437 out.write("struct c%s_s {\n" % cls)
2438 for m in of_g.ordered_members[cls]:
2439 if m in of_g.skip_members:
2440 continue
2441 entry = of_g.unified[cls]["union"][m]
2442 cof_type = type_to_cof_type(entry["m_type"])
2443 out.write(" %-20s %s;\n" % (cof_type, m))
2444 out.write("};\n\n");
2445
2446def gen_cof_structs(out):
2447 """
2448 Generate non-version specific (common) representation of structures
2449
2450 @param out The file to which to write the functions
2451 """
2452
2453 out.write("\n/* Common, unified OpenFlow structure representations */\n")
2454 for cls in of_g.standard_class_order:
2455 if cls in type_maps.inheritance_map:
2456 continue
2457 gen_cof_instance(out, cls)
2458
2459################################################################
2460#
2461# Generate code samples for applications.
2462#
2463################################################################
2464
2465def gen_code_samples(out, name):
2466 out.write("""
2467#if 0 /* Do not compile in */
2468/**
2469 * @file %(name)s
2470 *
2471 * These are code samples for inclusion in other components
2472 */
2473
2474""" % dict(name=name))
2475
2476 gen_jump_table_template(out)
2477 # These are messages that a switch might expect.
2478 msg_list = ["of_echo_request",
2479 "of_hello",
2480 "of_packet_in",
2481 "of_packet_out",
2482 "of_port_mod",
2483 "of_port_stats_request",
2484 "of_queue_get_config_request",
2485 "of_queue_stats_request",
2486 "of_flow_add",
2487 "of_flow_modify",
2488 "of_flow_modify_strict",
2489 "of_flow_delete",
2490 "of_flow_delete_strict",
2491 "of_get_config_request",
2492 "of_flow_stats_request",
2493 "of_barrier_request",
2494 "of_echo_reply",
2495 "of_aggregate_stats_request",
2496 "of_desc_stats_request",
2497 "of_table_stats_request",
2498 "of_features_request",
2499 "of_table_mod",
2500 "of_set_config",
2501 "of_experimenter",
2502 "of_experimenter_stats_request",
2503 "of_group_desc_stats_request",
2504 "of_group_features_stats_request",
2505 "of_role_request"]
2506
2507 gen_message_handler_templates(out, msgs=msg_list)
2508
2509 out.write("""
2510#endif
2511""")
2512
2513def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07002514 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07002515 unhandled="unhandled_message"):
2516 """
2517 Generate a template for a jump table.
2518 @param out The file to which to write the functions
2519 """
2520 out.write("""
2521/*
2522 * Simple jump table definition for message handling
2523 */
2524typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
2525typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
2526
2527/* Jump table template for message objects */
2528extern msg_jump_table_t jump_table;
2529
2530/* C-code template */
2531msg_jump_table_t jump_table = {
2532 %(unhandled)s, /* OF_OBJECT; place holder for generic object */
2533""" % dict(unhandled=unhandled, cxn_type=cxn_type))
2534 count = 0
2535 fn_name = unhandled
2536 for cls in of_g.ordered_messages:
2537 comma = ","
2538 count += 1
2539 if count == len(of_g.ordered_messages):
2540 comma = " "
2541 if not all_unhandled:
2542 fn_name = "%s_handler" % cls[3:]
2543 out.write(" %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002544
Rich Lanea06d0c32013-03-25 08:52:03 -07002545 out.write("};\n")
2546
2547def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07002548 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07002549 unhandled="unhandled_message"):
2550 out.write("""
2551/*
2552 * Simple switch statement for message handling
2553 */
2554
2555 switch (obj->object_id):
2556""")
2557 fn_name = unhandled
2558 for cls in of_g.ordered_messages:
2559 if not all_unhandled:
2560 fn_name = "%s_handler" % cls[3:]
2561 out.write("""
2562 case %(enum)s:
2563 rv = %(fn_name)s(cxn, obj);
2564 break;
2565""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
2566 out.write("""
2567 default:
2568 rv = LS_ERROR_PARAM;
2569 break;
2570 }
2571
2572 TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
2573
2574 return rv;
2575""")
2576
2577
2578def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
2579 unhandled="unhandled_message", msgs=None):
2580 gen_jump_table_template(out, False, cxn_type)
2581 out.write("""
2582/**
2583 * Function for unhandled message
2584 */
2585static int
2586unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
2587{
2588 (void)cxn;
2589 (void)obj;
2590 TRACE("Unhandled message %%p. Object id %%d", obj, obj->object_id);
2591
2592 return LS_ERROR_UNAVAIL;
2593}
2594""" % dict(unhandled=unhandled, cxn_type=cxn_type))
2595
2596 if not msgs:
2597 msgs = of_g.ordered_messages
2598 for cls in msgs:
2599 out.write("""
2600/**
2601 * Handle a %(s_cls)s message
2602 * @param cxn Connection handler for the owning connection
2603 * @param _obj Generic type object for the message to be coerced
2604 * @returns Error code
2605 */
2606
2607static int
2608%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
2609{
2610 %(cls)s_t *obj;
2611
2612 TRACE("Handling %(cls)s message: %%p.", obj);
2613 obj = (%(cls)s_t *)_obj;
2614
2615 /* Handle object of type %(cls)s_t */
2616
2617 return LS_ERROR_NONE;
2618}
2619""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
2620 gen_message_switch_stmt_tmeplate(out, False, cxn_type)