blob: 5cfba39adde6d6cbdc0d0e5dd74bc48d85d2e56b [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
39from c_gen.loxi_utils_legacy import config_check
Rich Lane92feca82013-12-10 15:57:13 -080040import loxi_globals
Rich Lanea06d0c32013-03-25 08:52:03 -070041
Andreas Wundsam542a13c2013-11-15 13:28:55 -080042import c_gen.identifiers as identifiers
Rich Lanea06d0c32013-03-25 08:52:03 -070043
Andreas Wundsam76db0062013-11-15 13:34:41 -080044# 'property' is for queues. Could be trouble
Rich Lanea06d0c32013-03-25 08:52:03 -070045
46################################################################
47#
48# Misc helper functions
49#
50################################################################
51
52def h_file_to_define(name):
53 """
54 Convert a .h file name to the define used for the header
55 """
56 h_name = name[:-2].upper()
57 h_name = "_" + h_name + "_H_"
58 return h_name
59
60def enum_name(cls):
61 """
62 Return the name used for an enum identifier for the given class
63 @param cls The class name
64 """
65 return loxi_utils.enum_name(cls)
66
67def member_returns_val(cls, m_name):
68 """
69 Should get accessor return a value rather than void
70 @param cls The class name
71 @param m_name The member name
Andreas Wundsam53256162013-05-02 14:05:53 -070072 @return True if of_g config and the specific member allow a
Rich Lanea06d0c32013-03-25 08:52:03 -070073 return value. Otherwise False
74 """
75 m_type = of_g.unified[cls]["union"][m_name]["m_type"]
Andreas Wundsam53256162013-05-02 14:05:53 -070076 return (config_check("get_returns") =="value" and
Rich Lanea06d0c32013-03-25 08:52:03 -070077 m_type in of_g.of_scalar_types)
78
79# TODO serialize match outside accessor?
80def accessor_return_type(a_type, m_type):
81 if loxi_utils.accessor_returns_error(a_type, m_type):
82 return "int WARN_UNUSED_RESULT"
83 else:
84 return "void"
85
86def accessor_return_success(a_type, m_type):
87 if loxi_utils.accessor_returns_error(a_type, m_type):
88 return "OF_ERROR_NONE"
89 else:
90 return ""
91
92################################################################
93#
94# Per-file generators, mapped to jump table below
95#
96################################################################
97
98def base_h_gen(out, name):
99 """
100 Generate code for base header file
101 @param out The file handle to write to
102 @param name The name of the file
103 """
104 common_top_matter(out, name)
105 base_h_content(out)
106 gen_object_enum(out)
107 out.write("""
108/****************************************************************
109 *
110 * Experimenter IDs
111 *
112 ****************************************************************/
113
114""")
115 for name, val in of_g.experimenter_name_to_id.items():
116 out.write("#define OF_EXPERIMENTER_ID_%s 0x%08x\n" %
117 (name.upper(), val))
118
119 out.write("""
120/****************************************************************
121 *
122 * OpenFlow Match version specific and generic defines
123 *
124 ****************************************************************/
125""")
126 c_match.gen_v4_match_compat(out)
127 c_match.gen_match_macros(out)
128 c_match.gen_oxm_defines(out)
129 out.write("\n#endif /* Base header file */\n")
130
131def identifiers_gen(out, filename):
132 """
133 Generate the macros for LOCI identifiers
134 @param out The file handle to write to
135 @param filename The name of the file
136 """
137 common_top_matter(out, filename)
138 out.write("""
139/**
140 * For each identifier from an OpenFlow header file, a Loxi version
141 * of the identifier is generated. For example, ofp_port_flood becomes
Andreas Wundsam53256162013-05-02 14:05:53 -0700142 * OF_PORT_DEST_FLOOD. Loxi provides the following macros related to
Rich Lanea06d0c32013-03-25 08:52:03 -0700143 * OpenFlow identifiers (using OF_IDENT_ as an example below):
144 * OF_IDENT_BY_VERSION(version) Get the value for the specific version
145 * OF_IDENT_SUPPORTED(version) Boolean: Is OF_IDENT defined for version
146 * OF_IDENT The common value across all versions if defined
147 * OF_IDENT_GENERIC A unique value across all OF identifiers
148 *
149 * For identifiers marked as flags, the following are also defined
150 * OF_IDENT_SET(flags, version)
151 * OF_IDENT_CLEAR(flags, version)
152 * OF_IDENT_TEST(flags, version)
153 *
154 * Notes:
155 *
156 * OF_IDENT_BY_VERSION(version) returns an undefined value
157 * if the passed version does not define OF_IDENT. It does not generate an
158 * error, nor record anything to the log file. If the value is the same
159 * across all defined versions, the version is ignored.
160 *
161 * OF_IDENT is only defined if the value is the same across all
162 * target LOXI versions FOR WHICH IT IS DEFINED. No error checking is
163 * done. This allows code to be written without requiring the version
164 * to be known or referenced when it doesn't matter. It does mean
165 * that when porting to a new version of OpenFlow, compile errors may
166 * occur. However, this is an indication that the existing code must
167 * be updated to account for a change in the semantics with the newly
168 * supported OpenFlow version.
169 *
170 * @fixme Currently we do not handle multi-bit flags or field values; for
171 * example, OF_TABLE_CONFIG_TABLE_MISS_CONTROLLER is the meaning for
172 * a zero value in the bits indicated by OF_TABLE_CONFIG_TABLE_MISS_MASK.
173 *
174 * @fixme Need to decide (or make a code gen option) on the requirement
175 * for defining OF_IDENT: Is it that all target versions define it and
176 * the agree? Or only that the versions which define it agree?
177 */
178""")
179
180 # Build value-by-version parameters and c_code
181 if len(of_g.target_version_list) > 1: # Supporting more than one version
182 vbv_params = []
183 vbv_code = ""
184 first = True
185 for version in of_g.target_version_list:
186 vbv_params.append("value_%s" % of_g.short_version_names[version])
187 if not first:
188 vbv_code += "\\\n "
189 else:
190 first = False
191 last_value = "value_%s" % of_g.short_version_names[version]
192 vbv_code += "((version) == %s) ? (%s) : " % \
193 (of_g.of_version_wire2name[version], last_value)
194 # @todo Using last value, can optimize out last ?
195 vbv_code += "(%s)" % last_value
196
197 out.write("""
198/**
199 * @brief True for the special case of all versions supported
200 */
201#define OF_IDENT_IN_ALL_VERSIONS 1 /* Indicates identifier in all versions */
202
203/**
204 * @brief General macro to map version to value where values given as params
205 *
206 * If unknown version is passed, use the latest version's value
207 */
208#define OF_VALUE_BY_VERSION(version, %s) \\
209 (%s)
210
211/**
212 * @brief Generic set a flag
213 */
214#define OF_FLAG_SET(flags, mask) (flags) = (flags) | (mask)
215
216/**
217 * @brief Generic test if a flag is set
218 */
219#define OF_FLAG_CLEAR(flags, mask) (flags) = (flags) & ~(mask)
220
221/**
222 * @brief Generic test if a flag is set
223 */
224#define OF_FLAG_TEST(flags, mask) ((flags) & (mask) ? 1 : 0)
225
226/**
227 * @brief Set a flag where the value is an enum indication of bit shift
228 */
229#define OF_FLAG_ENUM_SET(flags, e_val) OF_FLAG_SET(flags, 1 << (e_val))
230
231/**
232 * @brief Clear a flag where the value is an enum indication of bit shift
233 */
234#define OF_FLAG_ENUM_CLEAR(flags, e_val) OF_FLAG_CLEAR(flags, 1 << (e_val))
235
236/**
237 * @brief Test a flag where the value is an enum indication of bit shift
238 */
239#define OF_FLAG_ENUM_TEST(flags, e_val) OF_FLAG_TEST(flags, 1 << (e_val))
240""" % (", ".join(vbv_params), vbv_code))
241
242 # For each group of identifiers, bunch ident defns
243 count = 1
244 keys = of_g.identifiers_by_group.keys()
245 keys.sort()
246 for group in keys:
247 idents = of_g.identifiers_by_group[group]
248 idents.sort()
249 out.write("""
250/****************************************************************
Andreas Wundsam53256162013-05-02 14:05:53 -0700251 * Identifiers from %s
Rich Lanea06d0c32013-03-25 08:52:03 -0700252 *****************************************************************/
253""" % group)
254 for ident in idents:
255 info = of_g.identifiers[ident]
256
257 keys = info["values_by_version"].keys()
258 keys.sort()
259
260 out.write("""
261/*
262 * Defines for %(ident)s
263 * Original name %(ofp_name)s
264 */
265""" % dict(ident=ident, ofp_name=info["ofp_name"]))
266
267 # Generate supported versions macro
268 if len(keys) == len(of_g.target_version_list): # Defined for all
269 out.write("""\
270#define %(ident)s_SUPPORTED(version) OF_IDENT_IN_ALL_VERSIONS
271""" % dict(ident=ident))
272 else: # Undefined for some version
273 sup_list = []
274 for version in keys:
275 sup_list.append("((version) == %s)" %
276 of_g.of_version_wire2name[version])
277 out.write("""\
278#define %(ident)s_SUPPORTED(version) \\
279 (%(sup_str)s)
280""" % dict(ident=ident, sup_str=" || \\\n ".join(sup_list)))
281
282 # Generate value macro
283 if identifiers.defined_versions_agree(of_g.identifiers,
284 of_g.target_version_list,
285 ident):
286 out.write("""\
Rich Lanef3dc3962013-05-10 16:16:48 -0700287#define %(ident)s (%(value)#x)
288#define %(ident)s_BY_VERSION(version) (%(value)#x)
Rich Lanea06d0c32013-03-25 08:52:03 -0700289""" % dict(ident=ident,value=info["common_value"]))
290 else: # Values differ between versions
291 # Generate version check and value by version
292 val_list = []
293 # Order of params matters
294 for version in of_g.target_version_list:
295 if version in info["values_by_version"]:
296 value = info["values_by_version"][version]
297 else:
298 value = identifiers.UNDEFINED_IDENT_VALUE
Rich Lanef3dc3962013-05-10 16:16:48 -0700299 val_list.append("%#x" % value)
Rich Lanea06d0c32013-03-25 08:52:03 -0700300 out.write("""\
301#define %(ident)s_BY_VERSION(version) \\
302 OF_VALUE_BY_VERSION(version, %(val_str)s)
303""" % dict(ident=ident, val_str=", ".join(val_list)))
304 if flags.ident_is_flag(ident):
305 log("Treating %s as a flag" % ident)
306 out.write("""
307#define %(ident)s_SET(flags, version) \\
308 OF_FLAG_SET(flags, %(ident)s_BY_VERSION(version))
309#define %(ident)s_TEST(flags, version) \\
310 OF_FLAG_TEST(flags, %(ident)s_BY_VERSION(version))
311#define %(ident)s_CLEAR(flags, version) \\
312 OF_FLAG_CLEAR(flags, %(ident)s_BY_VERSION(version))
313""" % dict(ident=ident))
314
315 out.write("#define %(ident)s_GENERIC %(count)d\n"
316 % dict(ident=ident, count=count))
317 count += 1 # This count should probably be promoted higher
318
319 log("Generated %d identifiers" % (count - 1))
320 out.write("\n#endif /* Loci identifiers header file */\n")
321
322def base_h_external(out, filename):
323 """
324 Copy contents of external file to base header
325
326 The contents of the filename are copied literally into the
327 out file handler. This allows openflow common defines to
328 be entered into the LoxiGen code base. The content of this
329 code must depend only on standard C headers.
330 """
331 infile = open(filename, "r")
332 contents = infile.read()
333 out.write(contents)
334 infile.close()
335
336def match_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 c_match.match_h_top_matter(out, name)
343 c_match.gen_incompat_members(out)
344 c_match.gen_match_struct(out)
345 c_match.gen_match_comp(out)
346# c_match.gen_match_accessors(out)
347 out.write("\n#endif /* Match header file */\n")
348
349def top_h_gen(out, name):
350 """
351 Generate code for
352 @param out The file handle to write to
353 @param name The name of the file
354 """
355 external_h_top_matter(out, name)
356 out.write("""
357
358typedef enum loci_log_level {
359 LOCI_LOG_LEVEL_TRACE,
360 LOCI_LOG_LEVEL_VERBOSE,
361 LOCI_LOG_LEVEL_INFO,
362 LOCI_LOG_LEVEL_WARN,
363 LOCI_LOG_LEVEL_ERROR,
364 LOCI_LOG_LEVEL_MSG
365} loci_log_level_t;
366
367/**
368 * @brief Output a log message.
369 * @param level The log level.
370 * @param fname The function name.
371 * @param file The file name.
372 * @param line The line number.
373 * @param format The message format string.
374 */
375typedef int (*loci_logger_f)(loci_log_level_t level,
376 const char *fname, const char *file, int line,
377 const char *format, ...);
378
379/*
380 * This variable should be set by the user of the library to redirect logs to
381 * their log infrastructure. The default drops all logs.
382 */
383extern loci_logger_f loci_logger;
384
385/**
386 * Map a generic object to the underlying wire buffer
387 *
388 * Treat as private
389 */
390#define OF_OBJECT_TO_MESSAGE(obj) \\
391 ((of_message_t)(WBUF_BUF((obj)->wire_object.wbuf)))
392
393/**
394 * Macro for the fixed length part of an object
395 *
396 * @param obj The object whose extended length is being calculated
397 * @returns length in bytes of non-variable part of the object
398 */
399#define OF_OBJECT_FIXED_LENGTH(obj) \\
400 (of_object_fixed_len[(obj)->version][(obj)->object_id])
401
402/**
403 * Return the length of the object beyond its fixed length
404 *
405 * @param obj The object whose extended length is being calculated
406 * @returns length in bytes of non-variable part of the object
407 *
408 * Most variable length fields are alone at the end of a structure.
409 * Their length is a simple calculation, just the total length of
410 * the parent minus the length of the non-variable part of the
411 * parent's class type.
412 */
413
414#define OF_OBJECT_VARIABLE_LENGTH(obj) \\
415 ((obj)->length - OF_OBJECT_FIXED_LENGTH(obj))
416
417/* FIXME: Where do these go? */
418/* Low level maps btwn wire version + type and object ids */
419extern int of_message_is_stats_request(int type, int w_ver);
420extern int of_message_is_stats_reply(int type, int w_ver);
421extern int of_message_stats_reply_to_object_id(int stats_type, int w_ver);
422extern int of_message_stats_request_to_object_id(int stats_type, int w_ver);
423extern int of_message_type_to_object_id(int type, int w_ver);
424
425extern int of_wire_buffer_of_match_get(of_object_t *obj, int offset,
426 of_match_t *match);
427extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
428 of_match_t *match, int cur_len);
Rich Lanea06d0c32013-03-25 08:52:03 -0700429""")
430
431 # gen_base_types(out)
432
Rich Lanea06d0c32013-03-25 08:52:03 -0700433 gen_flow_add_setup_function_declarations(out)
434 if config_check("gen_fn_ptrs"): # Otherwise, all classes are from generic cls
435 gen_struct_definitions(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700436 gen_top_static_functions(out)
437 out.write("""
438/****************************************************************
439 *
440 * Declarations of maps between on-the-wire type values and LOCI identifiers
441 *
442 ****************************************************************/
443""")
444 c_type_maps.gen_type_maps_header(out)
445 c_type_maps.gen_type_data_header(out)
446 c_match.gen_declarations(out)
447 # @fixme Move debug stuff to own fn
448 out.write("""
449/**
450 * Macro to check consistency of length for top level objects
451 *
452 * If the object has no parent then its length should match the
453 * underlying wire buffer's current bytes.
454 */
455#define OF_LENGTH_CHECK_ASSERT(obj) \\
456 ASSERT(((obj)->parent != NULL) || \\
457 ((obj)->wire_object.wbuf == NULL) || \\
458 (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
459
460#define OF_DEBUG_DUMP
461#if defined(OF_DEBUG_DUMP)
462extern void dump_match(of_match_t *match);
463#endif /* OF_DEBUG_DUMP */
464""")
465
466 out.write("\n#endif /* Top header file */\n")
467
468def match_c_gen(out, name):
469 """
470 Generate code for
471 @param out The file handle to write to
472 @param name The name of the file
473 """
474 c_match.match_c_top_matter(out, name)
475 c_match.gen_match_conversions(out)
476 c_match.gen_serialize(out)
477 c_match.gen_deserialize(out)
478
Rich Lanea06d0c32013-03-25 08:52:03 -0700479def type_data_c_gen(out, name):
480 common_top_matter(out, name)
481 c_type_maps.gen_type_maps(out)
482 c_type_maps.gen_length_array(out)
Rich Lanef70be942013-07-18 13:33:14 -0700483 c_type_maps.gen_extra_length_array(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700484
485################################################################
486# Top Matter
487################################################################
488
489def common_top_matter(out, name):
490 loxi_utils.gen_c_copy_license(out)
491 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700492
Rich Lanea06d0c32013-03-25 08:52:03 -0700493/****************************************************************
494 * File: %s
495 *
496 * DO NOT EDIT
497 *
498 * This file is automatically generated
499 *
500 ****************************************************************/
501
502""" % name)
503
504 if name[-2:] == ".h":
505 out.write("""
506#if !defined(%(h)s)
507#define %(h)s
508
509""" % dict(h=h_file_to_define(name)))
510
511def base_h_content(out):
512 """
513 Generate base header file content
514
515 @param out The output file object
516 """
517
518 # @fixme Supported version should be generated based on input to LoxiGen
519
520 out.write("""
521/*
522 * Base OpenFlow definitions. These depend only on standard C headers
523 */
524#include <string.h>
525#include <stdint.h>
526
527/* g++ requires this to pick up PRI, etc.
528 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
529 */
530#if !defined(__STDC_FORMAT_MACROS)
531#define __STDC_FORMAT_MACROS
532#endif
533#include <inttypes.h>
534
535#include <stdlib.h>
536#include <assert.h>
537#include <loci/loci_idents.h>
538
539/**
540 * Macro to enable debugging for LOCI.
541 *
542 * This enables debug output to stdout.
543 */
544#define OF_DEBUG_ENABLE
545
546#if defined(OF_DEBUG_ENABLE)
547#include <stdio.h> /* Currently for debugging */
548#define FIXME(str) do { \\
549 fprintf(stderr, "%s\\n", str); \\
550 exit(1); \\
551 } while (0)
552#define debug printf
553#else
554#define FIXME(str)
555#define debug(str, ...)
556#endif /* OF_DEBUG_ENABLE */
557
558/**
559 * The type of a function used by the LOCI dump/show functions to
560 * output text. Essentially the same signature as fprintf. May
561 * be called many times per invocation of e.g. of_object_show().
562 */
563typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
564
565/**
566 * Check if a version is supported
567 */
568#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
569
570""")
571 gen_version_enum(out)
572 out.write("\n")
573
574 # for c_name in of_g.ofp_constants:
575 # val = str(of_g.ofp_constants[c_name])
576 # out.write("#define %s %s\n" % (c_name, val))
577 # out.write("\n")
578
579 out.write("""
580typedef enum of_error_codes_e {
581 OF_ERROR_NONE = 0,
582 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
583 OF_ERROR_PARAM = -2, /* Bad parameter */
584 OF_ERROR_VERSION = -3, /* Version not supported */
585 OF_ERROR_RANGE = -4, /* End of list indication */
586 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
587 OF_ERROR_PARSE = -6, /* Error in parsing data */
588 OF_ERROR_INIT = -7, /* Uninitialized data */
589 OF_ERROR_UNKNOWN = -8 /* Unknown error */
590} of_error_codes_t;
591
592#define OF_ERROR_STRINGS "none", \\
593 "resource", \\
594 "parameter", \\
595 "version", \\
596 "range", \\
597 "incompatible", \\
598 "parse", \\
599 "init", \\
600 "unknown"
601
Rich Laneb157b0f2013-03-27 13:55:28 -0700602extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700603
Rich Lane53757732013-02-23 17:00:10 -0800604#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700605/* #define ASSERT(val) assert(val) */
606#define FORCE_FAULT *(volatile int *)0 = 1
607#define ASSERT(val) if (!(val)) \\
608 fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
609 FORCE_FAULT
Rich Lane53757732013-02-23 17:00:10 -0800610#else
611#define ASSERT(val)
612#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700613
614/*
615 * Some LOCI object accessors can fail, and it's easy to forget to check.
616 * On certain compilers we can trigger a warning if the error code
617 * is ignored.
618 */
619#ifndef DISABLE_WARN_UNUSED_RESULT
620#ifdef __GNUC__
621#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
622#else
623#define WARN_UNUSED_RESULT
624#endif
625#else
626#define WARN_UNUSED_RESULT
627#endif
628
629typedef union of_generic_u of_generic_t;
630typedef struct of_object_s of_object_t;
631
632/* Define ipv4 address as uint32 */
633typedef uint32_t of_ipv4_t;
634
635/* Table ID is the OF standard uint8 */
636typedef uint8_t of_table_id_t;
637
638#define OF_MAC_ADDR_BYTES 6
639typedef struct of_mac_addr_s {
640 uint8_t addr[OF_MAC_ADDR_BYTES];
641} of_mac_addr_t;
642
643#define OF_IPV6_BYTES 16
644typedef struct of_ipv6_s {
645 uint8_t addr[OF_IPV6_BYTES];
646} of_ipv6_t;
647
648extern const of_mac_addr_t of_mac_addr_all_ones;
649extern const of_mac_addr_t of_mac_addr_all_zeros;
650
651extern const of_ipv6_t of_ipv6_all_ones;
652extern const of_ipv6_t of_ipv6_all_zeros;
653
654/**
655 * Generic zero and all-ones values of size 16 bytes.
656 *
657 * IPv6 is longest data type we worry about for comparisons
658 */
659#define of_all_zero_value of_ipv6_all_zeros
660#define of_all_ones_value of_ipv6_all_ones
661
662/**
663 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
664 */
665#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
666 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
667#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
668 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
669
670/* The octets object is a struct holding pointer and length */
671typedef struct of_octets_s {
672 uint8_t *data;
673 int bytes;
674} of_octets_t;
675
676/* Macro to convert an octet object to a pointer; currently trivial */
677#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
678#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
679#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
680#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
681
682/* Currently these are categorized as scalars */
683typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
684typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
685typedef char of_desc_str_t[OF_DESC_STR_LEN];
686typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
687
Rich Lane3b2fd832013-09-24 13:44:08 -0700688typedef struct of_bitmap_128_s {
689 uint64_t hi;
690 uint64_t lo;
691} of_bitmap_128_t;
692
Rich Lanea06d0c32013-03-25 08:52:03 -0700693/* These are types which change across versions. */
694typedef uint32_t of_port_no_t;
695typedef uint16_t of_fm_cmd_t;
696typedef uint64_t of_wc_bmap_t;
697typedef uint64_t of_match_bmap_t;
698
699#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
700#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
701#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
702#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
703#define MALLOC(bytes) malloc(bytes)
704#define FREE(ptr) free(ptr)
705
706/** Try an operation and return on failure. */
707#define OF_TRY(op) do { \\
708 int _rv; \\
709 if ((_rv = (op)) < 0) { \\
710 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
711 return _rv; \\
712 } \\
713 } while (0)
714
715/* The extent of an OF match object is determined by its length field, but
716 * aligned to 8 bytes
717 */
718
719#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
720
721#if __BYTE_ORDER == __BIG_ENDIAN
722#define U16_NTOH(val) (val)
723#define U32_NTOH(val) (val)
724#define U64_NTOH(val) (val)
725#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
726#define U16_HTON(val) (val)
727#define U32_HTON(val) (val)
728#define U64_HTON(val) (val)
729#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
730#else /* Little Endian */
731#define U16_NTOH(val) (((val) >> 8) | ((val) << 8))
732#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
733 (((val) & 0x00ff0000) >> 8) | \\
734 (((val) & 0x0000ff00) << 8) | \\
735 (((val) & 0x000000ff) << 24))
736#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
737 (((val) & 0x00ff000000000000LL) >> 40) | \\
738 (((val) & 0x0000ff0000000000LL) >> 24) | \\
739 (((val) & 0x000000ff00000000LL) >> 8) | \\
740 (((val) & 0x00000000ff000000LL) << 8) | \\
741 (((val) & 0x0000000000ff0000LL) << 24) | \\
742 (((val) & 0x000000000000ff00LL) << 40) | \\
743 (((val) & 0x00000000000000ffLL) << 56))
744#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
745#define U16_HTON(val) U16_NTOH(val)
746#define U32_HTON(val) U32_NTOH(val)
747#define U64_HTON(val) U64_NTOH(val)
748#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
749#endif
750
751/****************************************************************
752 *
753 * The following are internal definitions used by the automatically
754 * generated code. Users should not reference these definitions
755 * as they may change between versions of this code
756 *
757 ****************************************************************/
758
759#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
760 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
761#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
762#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
763 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
764
765#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
766 (FIXED_LEN + of_message_out_actions_len_get(obj))
767
768""")
769
770def external_h_top_matter(out, name):
771 """
772 Generate top matter for external header file
773
774 @param name The name of the output file
775 @param out The output file object
776 """
777 common_top_matter(out, name)
778 out.write("""
779#include <loci/loci_base.h>
780#include <loci/of_message.h>
781#include <loci/of_match.h>
782#include <loci/of_object.h>
Rich Lanedef2e512013-12-15 15:54:02 -0800783#include <loci/loci_classes.h>
Rich Lanea06d0c32013-03-25 08:52:03 -0700784
785/****************************************************************
786 *
787 * This file is divided into the following sections.
788 *
789 * A few object specific macros
790 * Class typedefs (no struct definitions)
791 * Per-data type accessor function typedefs
792 * Per-class new/delete function typedefs
793 * Per-class static delete functions
794 * Per-class, per-member accessor declarations
795 * Per-class structure definitions
796 * Generic union (inheritance) definitions
797 * Pointer set function declarations
798 * Some special case macros
799 *
800 ****************************************************************/
801""")
802
803def gen_top_static_functions(out):
804 out.write("""
805
806#define _MAX_PARENT_ITERATIONS 4
807/**
808 * Iteratively update parent lengths thru hierarchy
809 * @param obj The object whose length is being updated
810 * @param delta The difference between the current and new lengths
811 *
812 * Note that this includes updating the object itself. It will
813 * iterate thru parents.
814 *
815 * Assumes delta > 0.
816 */
817static inline void
818of_object_parent_length_update(of_object_t *obj, int delta)
819{
Rich Laneed79e0d2013-03-26 14:30:31 -0700820#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700821 int count = 0;
822 of_wire_buffer_t *wbuf; /* For debug asserts only */
Rich Laneed79e0d2013-03-26 14:30:31 -0700823#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700824
825 while (obj != NULL) {
826 ASSERT(count++ < _MAX_PARENT_ITERATIONS);
827 obj->length += delta;
828 if (obj->wire_length_set != NULL) {
829 obj->wire_length_set(obj, obj->length);
830 }
Rich Laneed79e0d2013-03-26 14:30:31 -0700831#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700832 wbuf = obj->wire_object.wbuf;
Rich Laneed79e0d2013-03-26 14:30:31 -0700833#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700834
835 /* Asserts for wire length checking */
836 ASSERT(obj->length + obj->wire_object.obj_offset <=
837 WBUF_CURRENT_BYTES(wbuf));
838 if (obj->parent == NULL) {
839 ASSERT(obj->length + obj->wire_object.obj_offset ==
840 WBUF_CURRENT_BYTES(wbuf));
841 }
842
843 obj = obj->parent;
844 }
845}
846""")
847
848################################################################
849#
850################################################################
851
852def gen_version_enum(out):
853 """
854 Generate the enumerated type for versions in LoxiGen
855 @param out The file object to which to write the decs
856
857 This just uses the wire versions for now
858 """
859 out.write("""
860/**
861 * Enumeration of OpenFlow versions
862 *
863 * The wire protocol numbers are currently used for values of the corresponding
864 * version identifiers.
865 */
866typedef enum of_version_e {
867 OF_VERSION_UNKNOWN = 0,
868""")
869
870 is_first = True
871 max = 0
872 for v in of_g.wire_ver_map:
873 if is_first:
874 is_first = False
875 else:
876 out.write(",\n")
877 if v > max:
878 max = v
879 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
880
881 out.write("""
882} of_version_t;
883
884/**
885 * @brief Use this when declaring arrays indexed by wire version
886 */
887#define OF_VERSION_ARRAY_MAX %d
888""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700889
Rich Lanea06d0c32013-03-25 08:52:03 -0700890def gen_object_enum(out):
891 """
892 Generate the enumerated type for object identification in LoxiGen
893 @param out The file object to which to write the decs
894 """
895 out.write("""
896
897/**
898 * Enumeration of OpenFlow objects
899 *
900 * We enumerate the OpenFlow objects used internally. Note that some
901 * message types are determined both by an outer type (message type like
902 * stats_request) and an inner type (port stats). These are different
903 * messages in ofC.
904 *
905 * These values are for internal use only. They will change with
906 * different versions of ofC.
907 */
908
909typedef enum of_object_id_e {
910 /* Root object type */
911 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
912 OF_OBJECT = 0, /* Generic, untyped object */
913
914 /* OpenFlow message objects */
915""")
916 last = 0
917 msg_count = 0
918 for cls in of_g.ordered_messages:
919 out.write(" %s = %d,\n" % (enum_name(cls),
920 of_g.unified[cls]["object_id"]))
921 msg_count = of_g.unified[cls]["object_id"] + 1
922
923 out.write("\n /* Non-message objects */\n")
924 for cls in of_g.ordered_non_messages:
925 out.write(" %s = %d,\n" % (enum_name(cls),
926 of_g.unified[cls]["object_id"]))
927 last = of_g.unified[cls]["object_id"]
928 out.write("\n /* List objects */\n")
929 for cls in of_g.ordered_list_objects:
930 out.write(" %s = %d,\n" % (enum_name(cls),
931 of_g.unified[cls]["object_id"]))
932 last = of_g.unified[cls]["object_id"]
933
934 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
935 for cls in of_g.ordered_pseudo_objects:
936 out.write(" %s = %d,\n" % (enum_name(cls),
937 of_g.unified[cls]["object_id"]))
938 last = of_g.unified[cls]["object_id"]
939
940 out.write("""
941 OF_OBJECT_COUNT = %d
942} of_object_id_t;
943
Rich Laneb157b0f2013-03-27 13:55:28 -0700944extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700945
946#define OF_MESSAGE_OBJECT_COUNT %d
947""" % ((last + 1), msg_count))
948
949 # Generate object type range checking for inheritance classes
950
951 # @fixme These should be determined algorithmicly
952 out.write("""
953/*
954 * Macros to check if an object ID is within an inheritance class range
955 */
956""")
957 # Alphabetical order for 'last'
958 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
959 of_oxm="OF_OXM_VLAN_VID_MASKED",
960 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
961 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
962 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
963 # @FIXME add meter_band ?
964 )
965 for cls, last in last_ids.items():
966 out.write("""
967#define %(enum)s_FIRST_ID (%(enum)s + 1)
968#define %(enum)s_LAST_ID %(last)s
969#define %(enum)s_VALID_ID(id) \\
970 ((id) >= %(enum)s_FIRST_ID && \\
971 (id) <= %(enum)s_LAST_ID)
972""" % dict(enum=enum_name(cls), last=last))
973 out.write("""
974/**
975 * Function to check a wire ID
976 * @param object_id The ID to check
977 * @param base_object_id The inheritance parent, if applicable
978 * @returns boolean: If base_object_id is an inheritance class, check if
979 * object_id is valid as a subclass. Otherwise return 1.
980 *
981 * Note: Could check that object_id == base_object_id in the
982 * second case.
983 */
984static inline int
985of_wire_id_valid(int object_id, int base_object_id) {
986 switch (base_object_id) {
987 case OF_ACTION:
988 return OF_ACTION_VALID_ID(object_id);
989 case OF_OXM:
990 return OF_OXM_VALID_ID(object_id);
991 case OF_QUEUE_PROP:
992 return OF_QUEUE_PROP_VALID_ID(object_id);
993 case OF_TABLE_FEATURE_PROP:
994 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
995 case OF_INSTRUCTION:
996 return OF_INSTRUCTION_VALID_ID(object_id);
997 default:
998 break;
999 }
1000 return 1;
1001}
1002""")
1003
Rich Lanea06d0c32013-03-25 08:52:03 -07001004################################################################
1005#
1006# Internal Utility Functions
1007#
1008################################################################
1009
1010
1011def acc_name(cls, m_name):
1012 """
1013 Generate the root name of an accessor function for typedef
1014 @param cls The class name
1015 @param m_name The member name
1016 """
1017 (m_type, get_rv) = get_acc_rv(cls, m_name)
1018 return "%s_%s" % (cls, m_type)
1019
1020def get_acc_rv(cls, m_name):
1021 """
1022 Determine the data type and return type for a get accessor.
1023
1024 The return type may be "void" or it may be the accessor type
1025 depending on the system configuration and on the data type.
1026
1027 @param cls The class name
1028 @param m_name The member name
1029 @return A pair (m_type, rv) where m_type is the unified type of the
1030 member and rv is the get_accessor return type
1031 """
1032 member = of_g.unified[cls]["union"][m_name]
1033 m_type = member["m_type"]
1034 rv = "int"
1035 if member_returns_val(cls, m_name):
1036 rv = m_type
1037 if m_type[-2:] == "_t":
1038 m_type = m_type[:-2]
1039
1040 return (m_type, rv)
1041
1042def param_list(cls, m_name, a_type):
1043 """
1044 Generate the parameter list (no parens) for an a_type accessor
1045 @param cls The class name
1046 @param m_name The member name
1047 @param a_type One of "set" or "get" or TBD
1048 """
1049 member = of_g.unified[cls]["union"][m_name]
1050 m_type = member["m_type"]
1051 params = ["%s_t *obj" % cls]
1052 if a_type == "set":
1053 if loxi_utils.type_is_scalar(m_type):
1054 params.append("%s %s" % (m_type, m_name))
1055 else:
1056 params.append("%s *%s" % (m_type, m_name))
1057 elif a_type in ["get", "bind"]:
1058 params.append("%s *%s" % (m_type, m_name))
1059 else:
1060 debug("Class %s, name %s Bad param list a_type: %s" %
1061 (cls, m_name, a_type))
1062 sys.exit(1)
1063 return params
1064
1065def typed_function_base(cls, m_name):
1066 """
1067 Generate the core name for accessors based on the type
1068 @param cls The class name
1069 @param m_name The member name
1070 """
1071 (m_type, get_rv) = get_acc_rv(cls, m_name)
1072 return "%s_%s" % (cls, m_type)
1073
1074def member_function_base(cls, m_name):
1075 """
1076 Generate the core name for accessors based on the member name
1077 @param cls The class name
1078 @param m_name The member name
1079 """
1080 return "%s_%s" % (cls, m_name)
1081
1082def field_ver_get(cls, m_name):
1083 """
1084 Generate a dict, indexed by wire version, giving a pair (type, offset)
1085
1086 @param cls The class name
1087 @param m_name The name of the class member
1088
1089 If offset is not known for m_name, the type
1090 A dict is used for more convenient indexing.
1091 """
1092 result = {}
1093
1094 for ver in of_g.unified[cls]:
1095 if type(ver) == type(0): # It's a version
1096 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1097 ref_ver = of_g.unified[cls][ver]["use_version"]
1098 members = of_g.unified[cls][ref_ver]["members"]
1099 else:
1100 members = of_g.unified[cls][ver]["members"]
1101 idx = loxi_utils.member_to_index(m_name, members)
1102 if (idx < 0):
1103 continue # Member not in this version
1104 m_type = members[idx]["m_type"]
1105 offset = members[idx]["offset"]
1106
1107 # If m_type is mixed, get wire version type from global data
1108 if m_type in of_g.of_mixed_types and \
1109 ver in of_g.of_mixed_types[m_type]:
1110 m_type = of_g.of_mixed_types[m_type][ver]
1111
1112 # add version to result list
1113 result[ver] = (m_type, offset)
1114
1115 return result
1116
1117def v3_match_offset_get(cls):
1118 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001119 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001120 otherwise return -1
1121 """
1122 result = field_ver_get(cls, "match")
1123 if of_g.VERSION_1_2 in result:
1124 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1125 return result[of_g.VERSION_1_2][1]
1126 return -1
1127
1128################################################################
1129#
1130# OpenFlow Object Definitions
1131#
1132################################################################
1133
1134
1135def gen_of_object_defs(out):
1136 """
1137 Generate low level of_object core operations
1138 @param out The file for output, already open
1139 """
1140
1141def gen_generics(out):
1142 for (cls, subclasses) in type_maps.inheritance_map.items():
1143 out.write("""
1144/**
1145 * Inheritance super class for %(cls)s
1146 *
1147 * This class is the union of %(cls)s classes. You can refer
1148 * to it untyped by refering to the member 'header' whose structure
1149 * is common across all sub-classes.
1150 */
1151
1152union %(cls)s_u {
1153 %(cls)s_header_t header; /* Generic instance */
1154""" % dict(cls=cls))
1155 for subcls in sorted(subclasses):
1156 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1157 out.write("};\n")
1158
1159def gen_struct_typedefs(out):
1160 """
1161 Generate typedefs for all struct objects
1162 @param out The file for output, already open
1163 """
1164
1165 out.write("\n/* LOCI inheritance parent typedefs */\n")
1166 for cls in type_maps.inheritance_map:
1167 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1168 out.write("\n/* LOCI object typedefs */\n")
1169 for cls in of_g.standard_class_order:
1170 if cls in type_maps.inheritance_map:
1171 continue
1172 if config_check("gen_fn_ptrs"):
1173 out.write("typedef struct %(cls)s_s %(cls)s_t;\n" % dict(cls=cls))
1174 else:
1175 template = "typedef of_object_t %(cls)s_t;\n"
1176 out.write(template % dict(cls=cls))
1177
1178 out.write("""
1179/****************************************************************
1180 *
1181 * Additional of_object defines
1182 * These are needed for some static inline ops, so we put them here.
1183 *
1184 ****************************************************************/
1185
1186/* Delete an OpenFlow object without reference to its type */
1187extern void of_object_delete(of_object_t *obj);
1188
1189""")
1190
1191def gen_generic_union(out):
1192 """
1193 Generate the generic union object composing all LOCI objects
1194
1195 @param out The file to which to write the decs
1196 """
1197 out.write("""
1198/**
1199 * The common LOCI object is a union of all possible objects.
1200 */
1201union of_generic_u {
1202 of_object_t object; /* Common base class with fundamental accessors */
1203
1204 /* Message objects */
1205""")
1206 for cls in of_g.ordered_messages:
1207 out.write(" %s_t %s;\n" % (cls, cls))
1208 out.write("\n /* Non-message composite objects */\n")
1209 for cls in of_g.ordered_non_messages:
1210 if cls in type_maps.inheritance_map:
1211 continue
1212 out.write(" %s_t %s;\n" % (cls, cls))
1213 out.write("\n /* List objects */\n")
1214 for cls in of_g.ordered_list_objects:
1215 out.write(" %s_t %s;\n" % (cls, cls))
1216 out.write("};\n")
1217
Rich Lanea06d0c32013-03-25 08:52:03 -07001218def gen_flow_add_setup_function_declarations(out):
1219 """
1220 Add the declarations for functions that can be initialized
1221 by a flow add. These are defined external to LOXI.
1222 """
1223
1224 out.write("""
1225/****************************************************************
1226 * Functions for objects that can be initialized by a flow add message.
1227 * These are defined in a non-autogenerated file
1228 ****************************************************************/
1229
1230/**
1231 * @brief Set up a flow removed message from the original add
1232 * @param obj The flow removed message being updated
1233 * @param flow_add The flow_add message to use
1234 *
1235 * Initialize the following fields of obj to be identical
1236 * to what was originally on the wire from the flow_add object:
1237 * match
1238 * cookie
1239 * priority
1240 * idle_timeout
1241 * hard_timeout
1242 *
1243 */
1244
1245extern int
1246of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1247 of_flow_add_t *flow_add);
1248
1249
1250/**
1251 * @brief Set up the packet in match structure from the original add
1252 * @param obj The packet in message being updated
1253 * @param flow_add The flow_add message to use
1254 * @returns Indigo error code. Does not return a version error if
1255 * the version does not require initializing obj.
1256 *
1257 * Initialize the match member of obj to be identical to what was originally
1258 * on the wire from the flow_add object. If applicable, the table ID is also
1259 * initialized from the flow_add object.
1260 *
1261 * This API applies to 1.2 and later only.
1262 */
1263
1264extern int
1265of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1266 of_flow_add_t *flow_add);
1267
1268
1269/**
1270 * @brief Set up the flow stats entry from the original add
1271 * @param obj The packet in message being updated
1272 * @param flow_add The flow_add message to use
1273 * @param effects Optional actions or instructions; see below.
1274 *
1275 * Initialize the following fields of obj to be identical
1276 * to what was originally on the wire from the flow_add object:
1277 * match
1278 * actions/instructions (effects)
1279 * cookie
1280 * priority
1281 * idle_timeout
1282 * hard_timeout
1283 *
Andreas Wundsam53256162013-05-02 14:05:53 -07001284 * Note that the actions/instructions of a flow may be modified by a
Rich Lanea06d0c32013-03-25 08:52:03 -07001285 * subsequent flow modify message. To facilitate implementations,
1286 * the "effects" parameter is provided. If effects is NULL, the
1287 * actions/instructions are taken from the flow_add message.
1288 * Otherwise, effects is coerced to the proper type (actions or
1289 * instructions) and used to init obj.
1290 */
1291
1292extern int
1293of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1294 of_flow_add_t *flow_add,
1295 of_object_t *effects);
1296""")
1297
1298def gen_struct_definitions(out):
1299 """
1300 Generate the declaration of all of_ C structures
1301
1302 @param out The file to which to write the decs
1303 """
1304
1305 # This should only get called if gen_fn_ptr is true in code_gen_config
1306 if not config_check("gen_fn_ptrs"):
1307 debug("Error: gen_struct_defs called, but no fn ptrs set")
1308 return
1309
1310 for cls in of_g.standard_class_order:
1311 if cls in type_maps.inheritance_map:
1312 continue # These are generated elsewhere
1313 note = ""
1314 if loxi_utils.class_is_message(cls):
1315 note = " /* Class is message */"
1316 out.write("struct %s_s {%s\n" % (cls, note))
1317 out.write(""" /* Common members */
1318%s
1319 /* Class specific members */
1320""" % of_g.base_object_members)
1321 if loxi_utils.class_is_list(cls):
1322 out.write("""
1323 %(cls)s_first_f first;
1324 %(cls)s_next_f next;
1325 %(cls)s_append_bind_f append_bind;
1326 %(cls)s_append_f append;
1327};
1328
1329""" % {"cls": cls})
1330 continue # All done with list object
1331
1332 # Else, not a list instance; add accessors for all data members
1333 for m_name in of_g.ordered_members[cls]:
1334 if m_name in of_g.skip_members:
1335 # These members (length, etc) are handled internally
1336 continue
1337 f_name = acc_name(cls, m_name)
1338 out.write(" %s_get_f %s;\n" % (f_name, m_name + "_get"))
1339 out.write(" %s_set_f %s;\n" % (f_name, m_name + "_set"))
1340 out.write("};\n\n")
1341
1342
1343################################################################
1344#
1345# List accessor code generation
1346#
1347# Currently these all implement copy on read semantics
1348#
1349################################################################
1350
1351def init_call(e_type, obj, ver, length, cw):
1352 """
1353 Generate the init call given the strings for params
1354 """
1355 hdr = "" # If inheritance type, coerce to hdr object
1356 obj_name = obj
1357 if e_type in type_maps.inheritance_map:
1358 hdr = "_header"
1359 obj_name = "(%s_header_t *)" % e_type + obj
1360
1361 return """\
1362%(e_type)s%(hdr)s_init(%(obj_name)s,
1363 %(ver)s, %(length)s, %(cw)s)\
1364""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1365 length=length, cw=cw)
1366
1367def gen_list_first(out, cls, e_type):
1368 """
1369 Generate the body of a list_first operation
1370 @param cls The class name for which code is being generated
1371 @param e_type The element type of the list
1372 @param out The file to which to write
1373 """
1374 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1375 if e_type in type_maps.inheritance_map:
1376 len_str = "obj->header.length"
1377 else:
1378 len_str = "obj->length"
1379
1380 out.write("""
1381/**
1382 * Associate an iterator with a list
1383 * @param list The list to iterate over
1384 * @param obj The list entry iteration pointer
1385 * @return OF_ERROR_RANGE if the list is empty (end of list)
1386 *
1387 * The obj instance is completely initialized. The caller is responsible
1388 * for cleaning up any wire buffers associated with obj before this call
1389 */
1390
1391int
1392%(cls)s_first(%(cls)s_t *list,
1393 %(e_type)s_t *obj)
1394{
1395 int rv;
1396
1397 %(i_call)s;
1398 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1399 return rv;
1400 }
1401""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1402
1403 # Special case flow_stats_entry lists
1404
1405 out.write("""
1406 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1407 list->length);
1408 if (%(len_str)s == 0) {
1409 return OF_ERROR_PARSE;
1410 }
1411
1412 return rv;
1413}
1414""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1415
1416
1417def gen_bind(out, cls, m_name, m_type):
1418 """
1419 Generate the body of a bind function
1420 @param out The file to which to write
1421 @param cls The class name for which code is being generated
1422 @param m_name The name of the data member
1423 @param m_type The type of the data member
1424 """
1425
1426 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1427
1428 i_call = init_call(e_type, "child", "parent->version", "0", "1")
1429
1430 out.write("""
1431/**
1432 * Bind the child object to the parent object for read processing
1433 * @param parent The parent object
1434 * @param child The child object
1435 *
1436 * The child obj instance is completely initialized.
1437 */
1438
1439int
1440%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
1441 %(e_type)s_t *child)
1442{
1443 int rv;
1444
1445 %(i_call)s;
1446
1447 /* Derive offset and length of child in parent */
Andreas Wundsam53256162013-05-02 14:05:53 -07001448 OF_TRY(of_object_child_attach(parent, child,
Rich Lanea06d0c32013-03-25 08:52:03 -07001449 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1450 return rv;
1451 }
1452""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1453
1454 # Special case flow_stats_entry lists
1455
1456 out.write("""
1457 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1458 list->length);
1459 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1460 return OF_ERROR_PARSE;
1461 }
1462
1463 return rv;
1464}
1465""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1466
1467
1468def gen_list_next(out, cls, e_type):
1469 """
1470 Generate the body of a list_next operation
1471 @param cls The class name for which code is being generated
1472 @param e_type The element type of the list
1473 @param out The file to which to write
1474 """
1475
1476 if e_type in type_maps.inheritance_map:
1477 len_str = "obj->header.length"
1478 else:
1479 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001480
Rich Lanea06d0c32013-03-25 08:52:03 -07001481 out.write("""
1482/**
1483 * Advance an iterator to the next element in a list
1484 * @param list The list being iterated
1485 * @param obj The list entry iteration pointer
1486 * @return OF_ERROR_RANGE if already at the last entry on the list
1487 *
1488 */
1489
1490int
1491%(cls)s_next(%(cls)s_t *list,
1492 %(e_type)s_t *obj)
1493{
1494 int rv;
1495
1496 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1497 return rv;
1498 }
1499
1500 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1501 list->length);
1502
1503 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1504 return OF_ERROR_PARSE;
1505 }
1506
1507 return rv;
1508}
1509""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1510
1511def gen_list_append(out, cls, e_type):
1512 """
1513 Generate the body of a list append functions
1514 @param cls The class name for which code is being generated
1515 @param e_type The element type of the list
1516 @param out The file to which to write
1517 """
1518
1519 out.write("""
1520/**
1521 * Set up to append an object of type %(e_type)s to an %(cls)s.
1522 * @param list The list that is prepared for append
1523 * @param obj Pointer to object to hold data to append
1524 *
1525 * The obj instance is completely initialized. The caller is responsible
1526 * for cleaning up any wire buffers associated with obj before this call.
1527 *
1528 * See the generic documentation for of_list_append_bind.
1529 */
1530
1531int
1532%(cls)s_append_bind(%(cls)s_t *list,
1533 %(e_type)s_t *obj)
1534{
1535 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1536}
1537
1538/**
1539 * Append an item to a %(cls)s list.
1540 *
1541 * This copies data from item and leaves item untouched.
1542 *
1543 * See the generic documentation for of_list_append.
1544 */
1545
1546int
1547%(cls)s_append(%(cls)s_t *list,
1548 %(e_type)s_t *item)
1549{
1550 return of_list_append((of_object_t *)list, (of_object_t *)item);
1551}
1552
1553""" % dict(cls=cls, e_type=e_type))
1554
1555def gen_list_accessors(out, cls):
1556 e_type = loxi_utils.list_to_entry_type(cls)
1557 gen_list_first(out, cls, e_type)
1558 gen_list_next(out, cls, e_type)
1559 gen_list_append(out, cls, e_type)
1560
1561################################################################
1562#
1563# Accessor Functions
1564#
1565################################################################
1566
Andreas Wundsam53256162013-05-02 14:05:53 -07001567
Rich Lanea06d0c32013-03-25 08:52:03 -07001568def gen_accessor_declarations(out):
1569 """
1570 Generate the declaration of each version independent accessor
1571
1572 @param out The file to which to write the decs
1573 """
1574
1575 out.write("""
1576/****************************************************************
1577 *
1578 * Unified, per-member accessor function declarations
1579 *
1580 ****************************************************************/
1581""")
1582 for cls in of_g.standard_class_order:
1583 if cls in type_maps.inheritance_map:
1584 continue
1585 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1586 for m_name in of_g.ordered_members[cls]:
1587 if m_name in of_g.skip_members:
1588 continue
1589 m_type = loxi_utils.member_base_type(cls, m_name)
1590 base_name = "%s_%s" % (cls, m_name)
1591 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1592 get_ret_type = accessor_return_type("get", m_type)
1593 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1594 set_ret_type = accessor_return_type("set", m_type)
1595 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1596 bind_ret_type = accessor_return_type("bind", m_type)
1597
1598 if loxi_utils.type_is_of_object(m_type):
1599 # Generate bind accessors, but not get accessor
1600 out.write("""
1601extern %(set_ret_type)s %(base_name)s_set(
1602 %(sparams)s);
1603extern %(bind_ret_type)s %(base_name)s_bind(
1604 %(bparams)s);
1605extern %(m_type)s *%(cls)s_%(m_name)s_get(
1606 %(cls)s_t *obj);
1607""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1608 m_name=m_name, m_type=m_type, cls=cls,
1609 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1610 else:
1611 out.write("""
1612extern %(set_ret_type)s %(base_name)s_set(
1613 %(sparams)s);
1614extern %(get_ret_type)s %(base_name)s_get(
1615 %(gparams)s);
1616""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1617 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001618
Rich Lanea06d0c32013-03-25 08:52:03 -07001619 if loxi_utils.class_is_list(cls):
1620 e_type = loxi_utils.list_to_entry_type(cls)
1621 out.write("""
1622extern int %(cls)s_first(
1623 %(cls)s_t *list, %(e_type)s_t *obj);
1624extern int %(cls)s_next(
1625 %(cls)s_t *list, %(e_type)s_t *obj);
1626extern int %(cls)s_append_bind(
1627 %(cls)s_t *list, %(e_type)s_t *obj);
1628extern int %(cls)s_append(
1629 %(cls)s_t *list, %(e_type)s_t *obj);
1630
1631/**
1632 * Iteration macro for list of type %(cls)s
1633 * @param list Pointer to the list being iterated over of
1634 * type %(cls)s
1635 * @param elt Pointer to an element of type %(e_type)s
1636 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1637 */
1638#define %(u_cls)s_ITER(list, elt, rv) \\
1639 for ((rv) = %(cls)s_first((list), (elt)); \\
1640 (rv) == OF_ERROR_NONE; \\
1641 (rv) = %(cls)s_next((list), (elt)))
1642""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1643
1644
1645def wire_accessor(m_type, a_type):
1646 """
1647 Returns the name of the a_type accessor for low level wire buff offset
1648 @param m_type The member type
1649 @param a_type The accessor type (set or get)
1650 """
1651 # Strip off _t if present
1652 if m_type in of_g.of_base_types:
1653 m_type = of_g.of_base_types[m_type]["short_name"]
1654 if m_type in of_g.of_mixed_types:
1655 m_type = of_g.of_mixed_types[m_type]["short_name"]
1656 if m_type[-2:] == "_t":
1657 m_type = m_type[:-2]
1658 if m_type == "octets":
1659 m_type = "octets_data"
1660 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1661
1662def get_len_macro(cls, m_type, version):
1663 """
1664 Get the length macro for m_type in cls
1665 """
1666 if m_type.find("of_match") == 0:
1667 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1668 if m_type.find("of_list_oxm") == 0:
1669 return "wire_match_len(obj, 0) - 4"
1670 if loxi_utils.class_is_tlv16(m_type):
1671 return "_TLV16_LEN(obj, offset)"
1672 if cls == "of_packet_out" and m_type == "of_list_action_t":
1673 return "_PACKET_OUT_ACTION_LEN(obj)"
1674 # Default is everything to the end of the object
1675 return "_END_LEN(obj, offset)"
1676
1677def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1678 """
1679 Generate the sub-object offset and length calculations for accessors
1680 @param out File being written
1681 @param m_name Name of member
1682 @param version Wire version being processed
1683 @param a_type The accessor type (set or get)
1684 @param m_type The original member type
1685 @param offset The offset of the object or -1 if not fixed
1686 """
1687 # determine offset
1688 o_str = "%d" % offset # Default is fixed length
1689 if offset == -1:
1690 # There are currently 4 special cases for this
1691 # In general, get offset and length of predecessor
1692 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1693 pass
1694 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1695 pass
1696 elif (cls == "of_packet_in" and m_name == "data"):
1697 pass
1698 elif (cls == "of_packet_out" and m_name == "data"):
1699 pass
1700 else:
1701 debug("Error: Unknown member with offset == -1")
1702 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1703 sys.exit(1)
1704 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1705
1706 out.write("""\
1707 offset = %s;
1708""" % o_str);
1709
1710 # This could be moved to main body but for version check
1711 if not loxi_utils.type_is_scalar(m_type):
1712 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1713 m_type == "of_match_t":
1714 len_macro = get_len_macro(cls, m_type, version)
1715 else:
1716 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1717 out.write(" cur_len = %s;\n" % len_macro)
1718 out.write(" break;\n")
1719
1720def length_of(m_type, version):
1721 """
1722 Return the length of a type based on the version
1723 """
1724 if m_type in of_g.of_mixed_types:
1725 m_type = of_g.of_mixed_types[m_type][version]
1726 if m_type in of_g.of_base_types:
1727 return of_g.of_base_types[m_type]["bytes"]
1728 if (m_type[:-2], version) in of_g.base_length:
1729 return of_g.base_length[(m_type[:-2], version)]
1730 print "Unknown length request", m_type, version
1731 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001732
Rich Lanea06d0c32013-03-25 08:52:03 -07001733
1734def gen_get_accessor_body(out, cls, m_type, m_name):
1735 """
1736 Generate the common operations for a get accessor
1737 """
1738 if loxi_utils.type_is_scalar(m_type):
1739 ver = "" # See if version required for scalar update
1740 if m_type in of_g.of_mixed_types:
1741 ver = "ver, "
1742 out.write("""\
1743 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1744""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1745
1746 if m_type == "of_port_no_t":
1747 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1748 elif m_type == "of_octets_t":
1749 out.write("""\
1750 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
1751 %(m_name)s->bytes = cur_len;
1752 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1753""" % dict(m_name=m_name))
1754 elif m_type == "of_match_t":
1755 out.write("""
1756 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
1757 match_octets.bytes = cur_len;
1758 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
1759 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
1760""" % dict(m_name=m_name))
1761 else:
1762 out.write("""
1763 /* Initialize child */
1764 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1765 /* Attach to parent */
1766 %(m_name)s->parent = (of_object_t *)obj;
1767 %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
1768 %(m_name)s->wire_object.obj_offset = abs_offset;
1769 %(m_name)s->wire_object.owned = 0;
1770 %(m_name)s->length = cur_len;
1771""" % dict(m_type=m_type[:-2], m_name=m_name))
1772
1773
1774def gen_set_accessor_body(out, cls, m_type, m_name):
1775 """
1776 Generate the contents of a set accessor
1777 """
1778 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1779 ver = "" # See if version required for scalar update
1780 if m_type in of_g.of_mixed_types:
1781 ver = "ver, "
1782 cur_len = "" # See if version required for scalar update
1783 if m_type == "of_octets_t":
1784 cur_len = ", cur_len"
1785 out.write("""\
1786 new_len = %(m_name)s->bytes;
1787 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1788""" % dict(m_name=m_name))
1789 out.write("""\
1790 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1791""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1792 m_name=m_name))
1793
1794 elif m_type == "of_match_t":
1795 out.write("""
1796 /* Match object */
1797 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1798 new_len = match_octets.bytes;
1799 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1800 match_octets.data, new_len);
1801 /* Free match serialized octets */
1802 FREE(match_octets.data);
1803""" % dict(m_name=m_name))
1804
1805 else: # Other object type
1806 out.write("\n /* LOCI object type */")
1807 # Need to special case OXM list
1808 out.write("""
1809 new_len = %(m_name)s->length;
1810 /* If underlying buffer already shared; nothing to do */
1811 if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
1812 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1813 /* Verify that the offsets are correct */
1814 ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1815 /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
1816 return %(ret_success)s;
1817 }
1818
1819 /* Otherwise, replace existing object in data buffer */
1820 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1821 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1822""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1823
1824 if not loxi_utils.type_is_scalar(m_type):
1825 if cls == "of_packet_out" and m_type == "of_list_action_t":
1826 out.write("""
1827 /* Special case for setting action lengths */
1828 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1829""" % dict(m_name=m_name))
1830 elif m_type not in ["of_match_t", "of_octets_t"]:
1831 out.write("""
1832 /* @fixme Shouldn't this precede copying value's data to buffer? */
1833 if (%(m_name)s->wire_length_set != NULL) {
1834 %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
1835 }
1836""" % dict(m_name=m_name))
1837 out.write("""
1838 /* Not scalar, update lengths if needed */
1839 delta = new_len - cur_len;
1840 if (delta != 0) {
1841 /* Update parent(s) */
1842 of_object_parent_length_update((of_object_t *)obj, delta);
1843 }
1844""")
1845
1846def obj_assert_check(cls):
1847 """
1848 The body of the assert check for an accessor
1849 We allow all versions of add/delete/modify to use the same accessors
1850 """
1851 if cls in ["of_flow_modify", "of_flow_modify_strict",
1852 "of_flow_delete", "of_flow_delete_strict",
1853 "of_flow_add"]:
1854 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1855 else:
1856 return "obj->object_id == %s" % cls.upper()
1857
1858def gen_of_object_get(out, cls, m_name, m_type):
1859 sub_cls = m_type[:-2]
1860 out.write("""
1861/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001862 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07001863 * a %(cls)s instance.
1864 *
1865 * @param obj Pointer to the source of type %(cls)s_t
1866 * @returns A pointer to a new instance of type %(m_type)s whose contents
1867 * match that of %(m_name)s from source
1868 * @returns NULL if an error occurs
1869 */
1870%(m_type)s *
1871%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
1872 %(m_type)s _%(m_name)s;
1873 %(m_type)s *_%(m_name)s_ptr;
1874
1875 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
1876 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
1877 return _%(m_name)s_ptr;
1878}
1879""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
1880
1881def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
1882 """
1883 Generate the body of a set or get accessor function
1884
1885 @param out The file to which to write the decs
1886 @param cls The class name
1887 @param m_name The member name
1888 @param ver_type_map Maps (type, offset) pairs to a list of versions
1889 @param a_type The accessor type, set or get
1890 @param m_type The original member type
1891
1892 The type values in ver_type_map are now ignored as we've pushed down
1893 the type munging to the lower level.
1894
1895 This is unified because the version switch case processing is the
1896 same for both set and get
1897 """
1898 out.write("""{
1899 of_wire_buffer_t *wbuf;
1900 int offset = 0; /* Offset of value relative to the start obj */
1901 int abs_offset; /* Offset of value relative to start of wbuf */
1902 of_version_t ver;
1903""")
1904
1905 if not loxi_utils.type_is_scalar(m_type):
1906 out.write("""\
1907 int cur_len = 0; /* Current length of object data */
1908""")
1909 if a_type == "set":
1910 out.write("""\
1911 int new_len, delta; /* For set, need new length and delta */
1912""")
1913
1914 # For match, need octet string for set/get
1915 if m_type == "of_match_t":
1916 out.write("""\
1917 of_octets_t match_octets; /* Serialized string for match */
1918""")
1919
1920 out.write("""
1921 ASSERT(%(assert_str)s);
1922 ver = obj->version;
1923 wbuf = OF_OBJECT_TO_WBUF(obj);
1924 ASSERT(wbuf != NULL);
1925
1926 /* By version, determine offset and current length (where needed) */
1927 switch (ver) {
1928""" % dict(assert_str=obj_assert_check(cls)))
1929
1930 for first in sorted(ver_type_map):
1931 (prev_t, prev_o) = ver_type_map[first]
1932 prev_len = length_of(prev_t, first)
1933 prev = first
1934 out.write(" case %s:\n" % of_g.wire_ver_map[first])
1935 break
1936
1937 for next in sorted(ver_type_map):
1938 if next == first:
1939 continue
1940
1941 (t, o) = ver_type_map[next]
1942 cur_len = length_of(t, next)
1943 if o == prev_o and cur_len == prev_len:
1944 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1945 continue
1946 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
1947 out.write(" case %s:\n" % of_g.wire_ver_map[next])
1948 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
1949
1950 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
1951 out.write("""\
1952 default:
1953 ASSERT(0);
1954 }
1955
1956 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
1957 ASSERT(abs_offset >= 0);
1958""")
1959 if not loxi_utils.type_is_scalar(m_type):
1960 out.write(" ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
1961
1962 # Now generate the common accessor code
1963 if a_type in ["get", "bind"]:
1964 gen_get_accessor_body(out, cls, m_type, m_name)
1965 else:
1966 gen_set_accessor_body(out, cls, m_type, m_name)
1967
1968 out.write("""
1969 OF_LENGTH_CHECK_ASSERT(obj);
1970
1971 return %s;
1972}
1973""" % accessor_return_success(a_type, m_type))
1974
1975def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
1976 """
1977 For generating the bind call for OF sub-objects
1978 """
1979
1980 params = ",\n ".join(param_list(cls, m_name, "bind"))
1981 out.write("""
1982/**
1983 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
1984 * member %(m_name)s
1985 * @param obj Pointer to an object of type %(cls)s.
1986 * @param %(m_name)s Pointer to the child object of type
1987 * %(m_type)s to be filled out.
1988 * \ingroup %(cls)s
1989 *
1990 * The parameter %(m_name)s is filled out to point to the same underlying
1991 * wire buffer as its parent.
1992 *
1993 */
1994""" % dict(m_name=m_name, cls=cls, m_type=m_type))
1995
1996 ret_type = accessor_return_type("bind", m_type)
1997 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
1998 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
1999
2000def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
2001 """
2002 For generating the get call for non- OF sub-objects
2003 """
2004 params = ",\n ".join(param_list(cls, m_name, "get"))
2005 out.write("""
2006/**
2007 * Get %(m_name)s from an object of type %(cls)s.
2008 * @param obj Pointer to an object of type %(cls)s.
2009 * @param %(m_name)s Pointer to the child object of type
2010 * %(m_type)s to be filled out.
2011 *
2012 */
2013""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2014
2015 ret_type = accessor_return_type("get", m_type)
2016 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
2017 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
2018
Rich Lanece2e4642013-12-15 12:05:45 -08002019def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002020 for m_name in of_g.ordered_members[cls]:
2021 if m_name in of_g.skip_members:
2022 continue
2023 m_type = loxi_utils.member_base_type(cls, m_name)
2024 ver_type_map = field_ver_get(cls, m_name)
2025
2026 # Generate get/bind pending on member type
2027 # FIXME: Does this do the right thing for match?
2028 if loxi_utils.type_is_of_object(m_type):
2029 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
2030 gen_of_object_get(out, cls, m_name, m_type)
2031 else:
2032 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
2033
2034 # Now generate set accessor for all objects
2035 params = ",\n ".join(param_list(cls, m_name, "set"))
2036 out.write("""
2037/**
2038 * Set %(m_name)s in an object of type %(cls)s.
2039 * @param obj Pointer to an object of type %(cls)s.
2040""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2041 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2042 out.write("""\
2043 * @param %(m_name)s The value to write into the object
2044 */
2045""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2046 else:
2047 out.write("""\
2048 * @param %(m_name)s Pointer to the child of type %(m_type)s.
2049 *
2050 * If the child's wire buffer is the same as the parent's, then
2051 * nothing is done as the changes have already been registered in the
2052 * parent. Otherwise, the data in the child's wire buffer is inserted
2053 * into the parent's and the appropriate lengths are updated.
2054 */
2055""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2056 ret_type = accessor_return_type("set", m_type)
2057 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
2058 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
2059
Rich Lanea06d0c32013-03-25 08:52:03 -07002060################################################################
2061#
2062# New/Delete Function Definitions
2063#
2064################################################################
2065
2066
2067################################################################
2068# First, some utility functions for new/delete
2069################################################################
2070
2071def del_function_proto(cls):
2072 """
2073 Return the prototype for the delete operator for the given class
2074 @param cls The class name
2075 """
2076 fn = "void\n"
2077 return fn
2078
2079
2080def instantiate_fn_ptrs(cls, ilvl, out):
2081 """
2082 Generate the C code to instantiate function pointers for a class
2083 @param cls The class name
2084 @param ilvl The base indentation level
2085 @param out The file to which to write the functions
2086 """
2087 for m_name in of_g.ordered_members[cls]:
2088 if m_name in of_g.skip_members:
2089 continue
2090 out.write(" " * ilvl + "obj->%s_get = %s_%s_get;\n" %
2091 (m_name, cls, m_name))
2092 out.write(" " * ilvl + "obj->%s_set = %s_%s_set;\n" %
2093 (m_name, cls, m_name))
2094
2095################################################################
2096# Routines to generate the body of new/delete functions
2097################################################################
2098
2099def gen_init_fn_body(cls, out):
2100 """
2101 Generate function body for init function
2102 @param cls The class name for the function
2103 @param out The file to which to write
2104 """
2105 if cls in type_maps.inheritance_map:
2106 param = "obj_p"
2107 else:
2108 param = "obj"
2109
2110 out.write("""
2111/**
2112 * Initialize an object of type %(cls)s.
2113 *
2114 * @param obj Pointer to the object to initialize
2115 * @param version The wire version to use for the object
2116 * @param bytes How many bytes in the object
2117 * @param clean_wire Boolean: If true, clear the wire object control struct
2118 *
2119 * If bytes < 0, then the default fixed length is used for the object
2120 *
2121 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07002122 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07002123 *
2124 * If anything other than 0 is passed in for the buffer size, the underlying
2125 * wire buffer will have 'grow' called.
2126 */
2127
2128void
2129%(cls)s_init(%(cls)s_t *%(param)s,
2130 of_version_t version, int bytes, int clean_wire)
2131{
2132""" % dict(cls=cls, param=param))
2133
2134 # Use an extra pointer to deal with inheritance classes
2135 if cls in type_maps.inheritance_map:
2136 out.write("""\
2137 %s_header_t *obj;
2138
2139 obj = &obj_p->header; /* Need instantiable subclass */
2140""" % cls)
2141
2142 out.write("""
2143 ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
2144 if (clean_wire) {
2145 MEMSET(obj, 0, sizeof(*obj));
2146 }
2147 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07002148 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002149 }
2150 obj->version = version;
2151 obj->length = bytes;
2152 obj->object_id = %(enum)s;
2153""" % dict(cls=cls, enum=enum_name(cls)))
2154 gen_coerce_ops(out, cls)
2155
2156 out.write("""
2157 /* Grow the wire buffer */
2158 if (obj->wire_object.wbuf != NULL) {
2159 int tot_bytes;
2160
2161 tot_bytes = bytes + obj->wire_object.obj_offset;
2162 of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
2163 }
2164}
2165
2166""")
2167
2168## @fixme This should also be updated once there is a map from
2169# class instance to wire length/type accessors
2170def gen_wire_push_fn(cls, out):
2171 """
2172 Generate the calls to push values into the wire buffer
2173 """
2174 if type_maps.class_is_virtual(cls):
2175 print "Push fn gen called for virtual class " + cls
2176 return
2177
2178 out.write("""
2179/**
2180 * Helper function to push values into the wire buffer
2181 */
2182static inline int
2183%(cls)s_push_wire_values(%(cls)s_t *obj)
2184{
2185""" % dict(cls=cls))
2186
Rich Lanebdd8e292013-12-06 17:37:39 -08002187 import loxi_globals
2188 uclass = loxi_globals.unified.class_by_name(cls)
2189 if uclass and not uclass.virtual and uclass.has_type_members:
2190 out.write("""
2191 %(cls)s_push_wire_types(obj);
2192""" % dict(cls=cls))
2193
Rich Lanea06d0c32013-03-25 08:52:03 -07002194 if loxi_utils.class_is_message(cls):
2195 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002196 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002197 of_message_t msg;
2198
2199 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002200 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002201 }
2202""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002203
Rich Lanea06d0c32013-03-25 08:52:03 -07002204 else: # Not a message
2205 if loxi_utils.class_is_tlv16(cls):
2206 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002207 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002208 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002209""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07002210
Rich Lanea06d0c32013-03-25 08:52:03 -07002211 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2212 out.write("""
2213 obj->wire_length_set((of_object_t *)obj, obj->length);
2214""")
2215
2216 if cls == "of_meter_stats":
2217 out.write("""
2218 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2219""" % dict(enum=enum_name(cls)))
2220
2221 out.write("""
2222 return OF_ERROR_NONE;
2223}
2224""")
2225
2226def gen_new_fn_body(cls, out):
2227 """
2228 Generate function body for new function
2229 @param cls The class name for the function
2230 @param out The file to which to write
2231 """
2232
2233 out.write("""
2234/**
2235 * \\defgroup %(cls)s %(cls)s
2236 */
2237""" % dict(cls=cls))
2238
2239 if not type_maps.class_is_virtual(cls):
2240 gen_wire_push_fn(cls, out)
2241
2242 out.write("""
2243/**
2244 * Create a new %(cls)s object
2245 *
2246 * @param version The wire version to use for the object
2247 * @return Pointer to the newly create object or NULL on error
2248 *
2249 * Initializes the new object with it's default fixed length associating
2250 * a new underlying wire buffer.
2251 *
2252 * Use new_from_message to bind an existing message to a message object,
2253 * or a _get function for non-message objects.
2254 *
2255 * \\ingroup %(cls)s
2256 */
2257
2258%(cls)s_t *
2259%(cls)s_new_(of_version_t version)
2260{
2261 %(cls)s_t *obj;
2262 int bytes;
2263
Rich Lanef70be942013-07-18 13:33:14 -07002264 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002265
2266 /* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
2267 if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
2268 return NULL;
2269 }
2270
2271 %(cls)s_init(obj, version, bytes, 0);
2272""" % dict(cls=cls, enum=enum_name(cls)))
2273 if not type_maps.class_is_virtual(cls):
2274 out.write("""
2275 if (%(cls)s_push_wire_values(obj) < 0) {
2276 FREE(obj);
2277 return NULL;
2278 }
2279""" % dict(cls=cls))
2280
2281 match_offset = v3_match_offset_get(cls)
2282 if match_offset >= 0:
2283 # Init length field for match object
2284 out.write("""
2285 /* Initialize match TLV for 1.2 */
2286 /* FIXME: Check 1.3 below */
2287 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2288 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2289 }
2290""" % dict(match_offset=match_offset))
2291 out.write("""
2292 return obj;
2293}
2294
2295#if defined(OF_OBJECT_TRACKING)
2296
2297/*
2298 * Tracking objects. Call the new function and then record location
2299 */
2300
2301%(cls)s_t *
2302%(cls)s_new_tracking(of_version_t version,
2303 const char *file, int line)
2304{
2305 %(cls)s_t *obj;
2306
2307 obj = %(cls)s_new_(version);
2308 of_object_track((of_object_t *)obj, file, line);
2309
2310 return obj;
2311}
2312#endif
2313""" % dict(cls=cls))
2314
2315
2316def gen_from_message_fn_body(cls, out):
2317 """
2318 Generate function body for from_message function
2319 @param cls The class name for the function
2320 @param out The file to which to write
2321 """
2322 out.write("""
2323/**
2324 * Create a new %(cls)s object and bind it to an existing message
2325 *
2326 * @param msg The message to bind the new object to
2327 * @return Pointer to the newly create object or NULL on error
2328 *
2329 * \ingroup %(cls)s
2330 */
2331
2332%(cls)s_t *
2333%(cls)s_new_from_message_(of_message_t msg)
2334{
2335 %(cls)s_t *obj = NULL;
2336 of_version_t version;
2337 int length;
2338
2339 if (msg == NULL) return NULL;
2340
2341 version = of_message_version_get(msg);
2342 if (!OF_VERSION_OKAY(version)) return NULL;
2343
2344 length = of_message_length_get(msg);
2345
2346 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2347 return NULL;
2348 }
2349
2350 %(cls)s_init(obj, version, 0, 0);
2351
2352 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2353 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2354 FREE(obj);
2355 return NULL;
2356 }
2357 obj->length = length;
2358 obj->version = version;
2359
2360 return obj;
2361}
2362
2363#if defined(OF_OBJECT_TRACKING)
2364
2365/*
2366 * Tracking objects. Call the new function and then record location
2367 */
2368
2369%(cls)s_t *
2370%(cls)s_new_from_message_tracking(of_message_t msg,
2371 const char *file, int line)
2372{
2373 %(cls)s_t *obj;
2374
2375 obj = %(cls)s_new_from_message_(msg);
2376 of_object_track((of_object_t *)obj, file, line);
2377
2378 return obj;
2379}
2380#endif
2381""" % dict(cls=cls))
2382
2383
2384################################################################
2385# Now the top level generator functions
2386################################################################
2387
2388def gen_new_function_declarations(out):
2389 """
2390 Gerenate the header file declarations for new operators for all classes
2391 @param out The file to which to write the decs
2392 """
2393
2394 out.write("""
2395/****************************************************************
2396 *
2397 * New operator declarations
2398 *
2399 * _new: Create a new object for writing; includes init
2400 * _new_from_message: Create a new instance of the object and bind the
2401 * message data to the object
2402 * _init: Initialize and optionally allocate buffer space for an
2403 * automatic instance
2404 *
2405 * _new and _from_message require a delete operation to be called
2406 * on the object.
2407 *
2408 ****************************************************************/
2409""")
2410 out.write("""
2411/*
2412 * If object tracking is enabled, map "new" and "new from msg"
2413 * calls to tracking versions; otherwise, directly to internal
2414 * versions of fns which have the same name but end in _.
2415 */
2416
2417#if defined(OF_OBJECT_TRACKING)
2418""")
2419 for cls in of_g.standard_class_order:
2420 out.write("""
2421extern %(cls)s_t *
2422 %(cls)s_new_tracking(of_version_t version,
2423 const char *file, int line);
2424#define %(cls)s_new(version) \\
2425 %(cls)s_new_tracking(version, \\
2426 __FILE__, __LINE__)
2427""" % dict(cls=cls))
2428 if loxi_utils.class_is_message(cls):
2429 out.write("""extern %(cls)s_t *
2430 %(cls)s_new_from_message_tracking(of_message_t msg,
2431 const char *file, int line);
2432#define %(cls)s_new_from_message(msg) \\
2433 %(cls)s_new_from_message_tracking(msg, \\
2434 __FILE__, __LINE__)
2435""" % dict(cls=cls))
2436
2437 out.write("""
2438#else /* No object tracking */
2439""")
2440 for cls in of_g.standard_class_order:
2441 out.write("""
2442#define %(cls)s_new(version) \\
2443 %(cls)s_new_(version)
2444""" % dict(cls=cls))
2445 if loxi_utils.class_is_message(cls):
2446 out.write("""#define %(cls)s_new_from_message(msg) \\
2447 %(cls)s_new_from_message_(msg)
2448""" % dict(cls=cls))
2449
2450 out.write("""
2451#endif /* Object tracking */
2452""")
2453
2454 for cls in of_g.standard_class_order:
2455 out.write("""
2456extern %(cls)s_t *
2457 %(cls)s_new_(of_version_t version);
2458""" % dict(cls=cls))
2459 if loxi_utils.class_is_message(cls):
2460 out.write("""extern %(cls)s_t *
2461 %(cls)s_new_from_message_(of_message_t msg);
2462""" % dict(cls=cls))
2463 out.write("""extern void %(cls)s_init(
2464 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2465""" % dict(cls=cls))
2466
2467 out.write("""
2468/****************************************************************
2469 *
2470 * Delete operator static inline definitions.
2471 * These are here for type checking purposes only
2472 *
2473 ****************************************************************/
2474""")
2475 for cls in of_g.standard_class_order:
2476# if cls in type_maps.inheritance_map:
2477# continue
2478 out.write("""
2479/**
2480 * Delete an object of type %(cls)s_t
2481 * @param obj An instance of type %(cls)s_t
2482 *
2483 * \ingroup %(cls)s
2484 */
2485static inline void
2486%(cls)s_delete(%(cls)s_t *obj) {
2487 of_object_delete((of_object_t *)(obj));
2488}
2489""" % dict(cls=cls))
2490
2491 out.write("""
2492typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
2493 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07002494extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07002495""")
2496
2497 out.write("""
2498/****************************************************************
2499 *
2500 * Function pointer initialization functions
2501 * These are part of the "coerce" type casting for objects
2502 *
2503 ****************************************************************/
2504""")
2505
2506#
2507# @fixme Not clear that these should all be set for virtual fns
2508#
2509# @fixme Clean up. should have a (language specific) map from class
2510# to length and type get/set functions
2511#
2512
2513def gen_coerce_ops(out, cls):
2514 out.write("""
2515 /* Set up the object's function pointers */
2516""")
2517
Rich Lane92feca82013-12-10 15:57:13 -08002518 uclass = loxi_globals.unified.class_by_name(cls)
2519 if uclass and not uclass.virtual and uclass.has_type_members:
2520 out.write("""
2521 obj->wire_type_set = %(cls)s_push_wire_types;
2522""" % dict(cls=cls))
2523
Rich Lanea06d0c32013-03-25 08:52:03 -07002524 if loxi_utils.class_is_message(cls):
2525 out.write("""
2526 obj->wire_length_get = of_object_message_wire_length_get;
2527 obj->wire_length_set = of_object_message_wire_length_set;
2528""")
2529 else:
2530 if loxi_utils.class_is_tlv16(cls):
2531 if not (cls in type_maps.inheritance_map): # Don't set for super
2532 out.write("""
2533 obj->wire_length_set = of_tlv16_wire_length_set;
Rich Lanea06d0c32013-03-25 08:52:03 -07002534""")
2535 out.write("""
2536 obj->wire_length_get = of_tlv16_wire_length_get;
2537""")
2538 if loxi_utils.class_is_action(cls):
2539 out.write("""
2540 obj->wire_type_get = of_action_wire_object_id_get;
2541""")
2542 if loxi_utils.class_is_action_id(cls):
2543 out.write("""
2544 obj->wire_type_get = of_action_id_wire_object_id_get;
2545""")
2546 if loxi_utils.class_is_instruction(cls):
2547 out.write("""
2548 obj->wire_type_get = of_instruction_wire_object_id_get;
2549""")
2550 if loxi_utils.class_is_queue_prop(cls):
2551 out.write("""
2552 obj->wire_type_get = of_queue_prop_wire_object_id_get;
2553""")
2554 if loxi_utils.class_is_table_feature_prop(cls):
2555 out.write("""
2556 obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
2557""")
2558 if loxi_utils.class_is_meter_band(cls):
2559 out.write("""
2560 obj->wire_type_get = of_meter_band_wire_object_id_get;
2561""")
2562 if loxi_utils.class_is_hello_elem(cls):
2563 out.write("""
2564 obj->wire_type_get = of_hello_elem_wire_object_id_get;
2565""")
2566 if loxi_utils.class_is_oxm(cls):
2567 out.write("""
2568 obj->wire_length_get = of_oxm_wire_length_get;
Rich Lanea06d0c32013-03-25 08:52:03 -07002569 obj->wire_type_get = of_oxm_wire_object_id_get;
Rich Lanea06d0c32013-03-25 08:52:03 -07002570""")
2571 if loxi_utils.class_is_u16_len(cls):
2572 out.write("""
2573 obj->wire_length_get = of_u16_len_wire_length_get;
2574 obj->wire_length_set = of_u16_len_wire_length_set;
2575""")
2576 if cls == "of_packet_queue":
2577 out.write("""
2578 obj->wire_length_get = of_packet_queue_wire_length_get;
2579 obj->wire_length_set = of_packet_queue_wire_length_set;
2580""")
2581# if cls == "of_list_meter_band_stats":
2582# out.write("""
2583# obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
2584#""")
2585 if cls == "of_meter_stats":
2586 out.write("""
2587 obj->wire_length_get = of_meter_stats_wire_length_get;
2588 obj->wire_length_set = of_meter_stats_wire_length_set;
2589""")
2590
2591 if config_check("gen_fn_ptrs"):
2592 if loxi_utils.class_is_list(cls):
2593 out.write("""
2594 obj->first = %(cls)s_first;
2595 obj->next = %(cls)s_next;
2596 obj->append = %(cls)s_append;
2597 obj->append_bind = %(cls)s_append_bind;
2598""" % dict(cls=cls))
2599 else:
2600 instantiate_fn_ptrs(cls, 4, out)
2601
Rich Laneb604e332013-12-15 13:23:51 -08002602def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002603 """
2604 Generate the new operator for all classes
2605
2606 @param out The file to which to write the functions
2607 """
2608
Rich Laneb604e332013-12-15 13:23:51 -08002609 gen_new_fn_body(cls, out)
2610 gen_init_fn_body(cls, out)
2611 if loxi_utils.class_is_message(cls):
2612 gen_from_message_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07002613
Rich Lanea06d0c32013-03-25 08:52:03 -07002614"""
2615Document generation functions
2616
2617The main reason this is here is to generate documentation per
2618accessor that indicates the versions that support the interface.
2619"""
2620
2621
2622def gen_accessor_doc(out, name):
2623 """
2624 Generate documentation for each accessor function that indicates
2625 the versions supporting the accessor.
2626 """
2627
2628 common_top_matter(out, name)
2629
2630 out.write("/* DOCUMENTATION ONLY */\n")
2631
2632 for cls in of_g.standard_class_order:
2633 if cls in type_maps.inheritance_map:
2634 pass # Check this
2635
2636 out.write("""
2637/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002638 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07002639 * accessors available in all versions unless noted otherwise
2640 *
2641""" % dict(cls=cls))
2642 if loxi_utils.class_is_list(cls):
2643 out.write("""\
2644 * @param first Function of type %(cls)s_first_f.
2645 * Setup a TBD class object to the first entry in the list
2646 * @param next Function of type %(cls)s_next_f.
2647 * Advance a TBD class object to the next entry in the list
2648 * @param append_bind Function of type %(cls)s_append_bind_f
2649 * Setup a TBD class object for append to the end of the current list
2650 * @param append Function of type @ref %(cls)s_append_f.
2651 * Copy an item to the end of a list
2652""" % dict(cls=cls))
2653
2654 for m_name in of_g.ordered_members[cls]:
2655 if m_name in of_g.skip_members:
2656 continue
2657 ver_type_map = field_ver_get(cls, m_name)
2658 (m_type, get_rv) = get_acc_rv(cls, m_name)
2659 if len(ver_type_map) == 3:
2660 # ver_string = "Available in all versions"
2661 ver_string = ""
2662 else:
2663 ver_string = "("
2664 for ver in sorted(ver_type_map):
2665 ver_string += " " + of_g.short_version_names[ver]
2666 ver_string += ")."
2667
2668 f_name = acc_name(cls, m_name)
2669 out.write("""\
2670 * @param %(m_name)s_get/set %(ver_string)s
2671 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
2672 * are of type %(f_name)s_get_f and _set_f.
2673 *
2674""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
2675
2676 out.write("""\
2677 */
2678typedef struct %(cls)s_s %(cls)s_t;
2679""" % dict(cls=cls))
2680
2681 out.write("#endif /* _LOCI_DOC_H_ */\n")
2682
2683################################################################
2684#
2685# For fun, here are some unified, traditional C structure representation
2686#
2687################################################################
2688
2689def gen_cof_to_wire(out):
2690 pass
2691
2692def gen_wire_to_cof(out):
2693 pass
2694
2695def gen_cof_instance(out, cls):
2696 out.write("struct c%s_s {\n" % cls)
2697 for m in of_g.ordered_members[cls]:
2698 if m in of_g.skip_members:
2699 continue
2700 entry = of_g.unified[cls]["union"][m]
2701 cof_type = type_to_cof_type(entry["m_type"])
2702 out.write(" %-20s %s;\n" % (cof_type, m))
2703 out.write("};\n\n");
2704
2705def gen_cof_structs(out):
2706 """
2707 Generate non-version specific (common) representation of structures
2708
2709 @param out The file to which to write the functions
2710 """
2711
2712 out.write("\n/* Common, unified OpenFlow structure representations */\n")
2713 for cls in of_g.standard_class_order:
2714 if cls in type_maps.inheritance_map:
2715 continue
2716 gen_cof_instance(out, cls)
2717
2718################################################################
2719#
2720# Generate code samples for applications.
2721#
2722################################################################
2723
2724def gen_code_samples(out, name):
2725 out.write("""
2726#if 0 /* Do not compile in */
2727/**
2728 * @file %(name)s
2729 *
2730 * These are code samples for inclusion in other components
2731 */
2732
2733""" % dict(name=name))
2734
2735 gen_jump_table_template(out)
2736 # These are messages that a switch might expect.
2737 msg_list = ["of_echo_request",
2738 "of_hello",
2739 "of_packet_in",
2740 "of_packet_out",
2741 "of_port_mod",
2742 "of_port_stats_request",
2743 "of_queue_get_config_request",
2744 "of_queue_stats_request",
2745 "of_flow_add",
2746 "of_flow_modify",
2747 "of_flow_modify_strict",
2748 "of_flow_delete",
2749 "of_flow_delete_strict",
2750 "of_get_config_request",
2751 "of_flow_stats_request",
2752 "of_barrier_request",
2753 "of_echo_reply",
2754 "of_aggregate_stats_request",
2755 "of_desc_stats_request",
2756 "of_table_stats_request",
2757 "of_features_request",
2758 "of_table_mod",
2759 "of_set_config",
2760 "of_experimenter",
2761 "of_experimenter_stats_request",
2762 "of_group_desc_stats_request",
2763 "of_group_features_stats_request",
2764 "of_role_request"]
2765
2766 gen_message_handler_templates(out, msgs=msg_list)
2767
2768 out.write("""
2769#endif
2770""")
2771
2772def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07002773 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07002774 unhandled="unhandled_message"):
2775 """
2776 Generate a template for a jump table.
2777 @param out The file to which to write the functions
2778 """
2779 out.write("""
2780/*
2781 * Simple jump table definition for message handling
2782 */
2783typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
2784typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
2785
2786/* Jump table template for message objects */
2787extern msg_jump_table_t jump_table;
2788
2789/* C-code template */
2790msg_jump_table_t jump_table = {
2791 %(unhandled)s, /* OF_OBJECT; place holder for generic object */
2792""" % dict(unhandled=unhandled, cxn_type=cxn_type))
2793 count = 0
2794 fn_name = unhandled
2795 for cls in of_g.ordered_messages:
2796 comma = ","
2797 count += 1
2798 if count == len(of_g.ordered_messages):
2799 comma = " "
2800 if not all_unhandled:
2801 fn_name = "%s_handler" % cls[3:]
2802 out.write(" %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002803
Rich Lanea06d0c32013-03-25 08:52:03 -07002804 out.write("};\n")
2805
2806def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07002807 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07002808 unhandled="unhandled_message"):
2809 out.write("""
2810/*
2811 * Simple switch statement for message handling
2812 */
2813
2814 switch (obj->object_id):
2815""")
2816 fn_name = unhandled
2817 for cls in of_g.ordered_messages:
2818 if not all_unhandled:
2819 fn_name = "%s_handler" % cls[3:]
2820 out.write("""
2821 case %(enum)s:
2822 rv = %(fn_name)s(cxn, obj);
2823 break;
2824""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
2825 out.write("""
2826 default:
2827 rv = LS_ERROR_PARAM;
2828 break;
2829 }
2830
2831 TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
2832
2833 return rv;
2834""")
2835
2836
2837def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
2838 unhandled="unhandled_message", msgs=None):
2839 gen_jump_table_template(out, False, cxn_type)
2840 out.write("""
2841/**
2842 * Function for unhandled message
2843 */
2844static int
2845unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
2846{
2847 (void)cxn;
2848 (void)obj;
2849 TRACE("Unhandled message %%p. Object id %%d", obj, obj->object_id);
2850
2851 return LS_ERROR_UNAVAIL;
2852}
2853""" % dict(unhandled=unhandled, cxn_type=cxn_type))
2854
2855 if not msgs:
2856 msgs = of_g.ordered_messages
2857 for cls in msgs:
2858 out.write("""
2859/**
2860 * Handle a %(s_cls)s message
2861 * @param cxn Connection handler for the owning connection
2862 * @param _obj Generic type object for the message to be coerced
2863 * @returns Error code
2864 */
2865
2866static int
2867%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
2868{
2869 %(cls)s_t *obj;
2870
2871 TRACE("Handling %(cls)s message: %%p.", obj);
2872 obj = (%(cls)s_t *)_obj;
2873
2874 /* Handle object of type %(cls)s_t */
2875
2876 return LS_ERROR_NONE;
2877}
2878""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
2879 gen_message_switch_stmt_tmeplate(out, False, cxn_type)