blob: 7d3e0d72f03d79b440568094bd693d9bc7e9b953 [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
433 gen_struct_typedefs(out)
434 gen_acc_pointer_typedefs(out)
435 gen_new_function_declarations(out)
436 if config_check("gen_unified_fns"):
437 gen_accessor_declarations(out)
438
439 gen_common_struct_definitions(out)
440 gen_flow_add_setup_function_declarations(out)
441 if config_check("gen_fn_ptrs"): # Otherwise, all classes are from generic cls
442 gen_struct_definitions(out)
443 gen_generic_union(out)
444 gen_generics(out)
445 gen_top_static_functions(out)
446 out.write("""
447/****************************************************************
448 *
449 * Declarations of maps between on-the-wire type values and LOCI identifiers
450 *
451 ****************************************************************/
452""")
453 c_type_maps.gen_type_maps_header(out)
454 c_type_maps.gen_type_data_header(out)
455 c_match.gen_declarations(out)
456 # @fixme Move debug stuff to own fn
457 out.write("""
458/**
459 * Macro to check consistency of length for top level objects
460 *
461 * If the object has no parent then its length should match the
462 * underlying wire buffer's current bytes.
463 */
464#define OF_LENGTH_CHECK_ASSERT(obj) \\
465 ASSERT(((obj)->parent != NULL) || \\
466 ((obj)->wire_object.wbuf == NULL) || \\
467 (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
468
469#define OF_DEBUG_DUMP
470#if defined(OF_DEBUG_DUMP)
471extern void dump_match(of_match_t *match);
472#endif /* OF_DEBUG_DUMP */
473""")
474
475 out.write("\n#endif /* Top header file */\n")
476
477def match_c_gen(out, name):
478 """
479 Generate code for
480 @param out The file handle to write to
481 @param name The name of the file
482 """
483 c_match.match_c_top_matter(out, name)
484 c_match.gen_match_conversions(out)
485 c_match.gen_serialize(out)
486 c_match.gen_deserialize(out)
487
Rich Lanea06d0c32013-03-25 08:52:03 -0700488def top_c_gen(out, name):
489 """
490 Generate code for
491 @param out The file handle to write to
492 @param name The name of the file
493 """
494 common_top_matter(out, name)
495 # Generic C code that needs to go into loci.c can go here.
496 out.write("""
497/****************************************************************
498 *
499 * This file is divided into the following sections.
500 *
501 * Instantiate strings such as object names
502 * Special case macros for low level object access
503 * Per-class, per-member accessor definitions
504 * Per-class new/init function definitions
505 * Per-class new/init pointer instantiations
506 * Instantiate "set map" for pointer set fns
507 *
508 ****************************************************************/
509
Rich Lane34f40c72013-03-28 10:36:57 -0700510#ifdef __GNUC__
YAMAMOTO Takashi896e8782013-07-02 08:37:08 +0900511#ifdef __linux__
512/* glibc */
Rich Lane34f40c72013-03-28 10:36:57 -0700513#include <features.h>
YAMAMOTO Takashi896e8782013-07-02 08:37:08 +0900514#else
515/* NetBSD etc */
516#include <sys/cdefs.h>
517#ifdef __GNUC_PREREQ__
518#define __GNUC_PREREQ __GNUC_PREREQ__
519#endif
520#endif
521
522#ifndef __GNUC_PREREQ
523/* fallback */
524#define __GNUC_PREREQ(maj, min) 0
525#endif
Rich Lane34f40c72013-03-28 10:36:57 -0700526
527#if __GNUC_PREREQ(4,4)
Rich Lane12192032013-02-24 18:22:44 -0800528#pragma GCC optimize ("s")
Rich Lane34f40c72013-03-28 10:36:57 -0700529#endif
530
531#if __GNUC_PREREQ(4,6)
Rich Lane45676eb2013-03-26 14:28:31 -0700532#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
Rich Lane9d77b592013-03-27 11:28:10 -0700533#endif
Rich Lane12192032013-02-24 18:22:44 -0800534
Rich Lane34f40c72013-03-28 10:36:57 -0700535#endif
536
Rich Lanea06d0c32013-03-25 08:52:03 -0700537#include <loci/loci.h>
538#include <loci/of_object.h>
539#include "loci_log.h"
Rich Lanebdd8e292013-12-06 17:37:39 -0800540#include "loci_push_wire_types.h"
Rich Lanea407b912013-12-15 11:53:35 -0800541#include "loci_int.h"
Rich Lanea06d0c32013-03-25 08:52:03 -0700542
543""")
544 gen_object_enum_str(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700545 gen_init_map(out)
546 out.write("\n/* This code should be broken out to a different file */\n")
547 gen_setup_from_add_fns(out)
548
549def type_data_c_gen(out, name):
550 common_top_matter(out, name)
551 c_type_maps.gen_type_maps(out)
552 c_type_maps.gen_length_array(out)
Rich Lanef70be942013-07-18 13:33:14 -0700553 c_type_maps.gen_extra_length_array(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700554
555################################################################
556# Top Matter
557################################################################
558
559def common_top_matter(out, name):
560 loxi_utils.gen_c_copy_license(out)
561 out.write("""\
Rich Laned983aa52013-06-13 11:48:37 -0700562
Rich Lanea06d0c32013-03-25 08:52:03 -0700563/****************************************************************
564 * File: %s
565 *
566 * DO NOT EDIT
567 *
568 * This file is automatically generated
569 *
570 ****************************************************************/
571
572""" % name)
573
574 if name[-2:] == ".h":
575 out.write("""
576#if !defined(%(h)s)
577#define %(h)s
578
579""" % dict(h=h_file_to_define(name)))
580
581def base_h_content(out):
582 """
583 Generate base header file content
584
585 @param out The output file object
586 """
587
588 # @fixme Supported version should be generated based on input to LoxiGen
589
590 out.write("""
591/*
592 * Base OpenFlow definitions. These depend only on standard C headers
593 */
594#include <string.h>
595#include <stdint.h>
596
597/* g++ requires this to pick up PRI, etc.
598 * See http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
599 */
600#if !defined(__STDC_FORMAT_MACROS)
601#define __STDC_FORMAT_MACROS
602#endif
603#include <inttypes.h>
604
605#include <stdlib.h>
606#include <assert.h>
607#include <loci/loci_idents.h>
608
609/**
610 * Macro to enable debugging for LOCI.
611 *
612 * This enables debug output to stdout.
613 */
614#define OF_DEBUG_ENABLE
615
616#if defined(OF_DEBUG_ENABLE)
617#include <stdio.h> /* Currently for debugging */
618#define FIXME(str) do { \\
619 fprintf(stderr, "%s\\n", str); \\
620 exit(1); \\
621 } while (0)
622#define debug printf
623#else
624#define FIXME(str)
625#define debug(str, ...)
626#endif /* OF_DEBUG_ENABLE */
627
628/**
629 * The type of a function used by the LOCI dump/show functions to
630 * output text. Essentially the same signature as fprintf. May
631 * be called many times per invocation of e.g. of_object_show().
632 */
633typedef int (*loci_writer_f)(void *cookie, const char *fmt, ...);
634
635/**
636 * Check if a version is supported
637 */
638#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
639
640""")
641 gen_version_enum(out)
642 out.write("\n")
643
644 # for c_name in of_g.ofp_constants:
645 # val = str(of_g.ofp_constants[c_name])
646 # out.write("#define %s %s\n" % (c_name, val))
647 # out.write("\n")
648
649 out.write("""
650typedef enum of_error_codes_e {
651 OF_ERROR_NONE = 0,
652 OF_ERROR_RESOURCE = -1, /* Could not allocate space */
653 OF_ERROR_PARAM = -2, /* Bad parameter */
654 OF_ERROR_VERSION = -3, /* Version not supported */
655 OF_ERROR_RANGE = -4, /* End of list indication */
656 OF_ERROR_COMPAT = -5, /* Incompatible assignment */
657 OF_ERROR_PARSE = -6, /* Error in parsing data */
658 OF_ERROR_INIT = -7, /* Uninitialized data */
659 OF_ERROR_UNKNOWN = -8 /* Unknown error */
660} of_error_codes_t;
661
662#define OF_ERROR_STRINGS "none", \\
663 "resource", \\
664 "parameter", \\
665 "version", \\
666 "range", \\
667 "incompatible", \\
668 "parse", \\
669 "init", \\
670 "unknown"
671
Rich Laneb157b0f2013-03-27 13:55:28 -0700672extern const char *const of_error_strings[];
Rich Lanea06d0c32013-03-25 08:52:03 -0700673
Rich Lane53757732013-02-23 17:00:10 -0800674#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700675/* #define ASSERT(val) assert(val) */
676#define FORCE_FAULT *(volatile int *)0 = 1
677#define ASSERT(val) if (!(val)) \\
678 fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
679 FORCE_FAULT
Rich Lane53757732013-02-23 17:00:10 -0800680#else
681#define ASSERT(val)
682#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700683
684/*
685 * Some LOCI object accessors can fail, and it's easy to forget to check.
686 * On certain compilers we can trigger a warning if the error code
687 * is ignored.
688 */
689#ifndef DISABLE_WARN_UNUSED_RESULT
690#ifdef __GNUC__
691#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
692#else
693#define WARN_UNUSED_RESULT
694#endif
695#else
696#define WARN_UNUSED_RESULT
697#endif
698
699typedef union of_generic_u of_generic_t;
700typedef struct of_object_s of_object_t;
701
702/* Define ipv4 address as uint32 */
703typedef uint32_t of_ipv4_t;
704
705/* Table ID is the OF standard uint8 */
706typedef uint8_t of_table_id_t;
707
708#define OF_MAC_ADDR_BYTES 6
709typedef struct of_mac_addr_s {
710 uint8_t addr[OF_MAC_ADDR_BYTES];
711} of_mac_addr_t;
712
713#define OF_IPV6_BYTES 16
714typedef struct of_ipv6_s {
715 uint8_t addr[OF_IPV6_BYTES];
716} of_ipv6_t;
717
718extern const of_mac_addr_t of_mac_addr_all_ones;
719extern const of_mac_addr_t of_mac_addr_all_zeros;
720
721extern const of_ipv6_t of_ipv6_all_ones;
722extern const of_ipv6_t of_ipv6_all_zeros;
723
724/**
725 * Generic zero and all-ones values of size 16 bytes.
726 *
727 * IPv6 is longest data type we worry about for comparisons
728 */
729#define of_all_zero_value of_ipv6_all_zeros
730#define of_all_ones_value of_ipv6_all_ones
731
732/**
733 * Non-zero/all ones check for arbitrary type of size <= 16 bytes
734 */
735#define OF_VARIABLE_IS_NON_ZERO(_ptr) \\
736 (MEMCMP(&of_all_zero_value, (_ptr), sizeof(*(_ptr))))
737#define OF_VARIABLE_IS_ALL_ONES(_ptr) \\
738 (!MEMCMP(&of_all_ones_value, (_ptr), sizeof(*(_ptr))))
739
740/* The octets object is a struct holding pointer and length */
741typedef struct of_octets_s {
742 uint8_t *data;
743 int bytes;
744} of_octets_t;
745
746/* Macro to convert an octet object to a pointer; currently trivial */
747#define OF_OCTETS_POINTER_GET(octet_ptr) ((octet_ptr)->data)
748#define OF_OCTETS_POINTER_SET(octet_ptr, ptr) (octet_ptr)->data = (ptr)
749#define OF_OCTETS_BYTES_GET(octet_ptr) ((octet_ptr)->bytes)
750#define OF_OCTETS_BYTES_SET(octet_ptr, bytes) (octet_ptr)->bytes = (bytes)
751
752/* Currently these are categorized as scalars */
753typedef char of_port_name_t[OF_MAX_PORT_NAME_LEN];
754typedef char of_table_name_t[OF_MAX_TABLE_NAME_LEN];
755typedef char of_desc_str_t[OF_DESC_STR_LEN];
756typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
757
Rich Lane3b2fd832013-09-24 13:44:08 -0700758typedef struct of_bitmap_128_s {
759 uint64_t hi;
760 uint64_t lo;
761} of_bitmap_128_t;
762
Rich Lanea06d0c32013-03-25 08:52:03 -0700763/* These are types which change across versions. */
764typedef uint32_t of_port_no_t;
765typedef uint16_t of_fm_cmd_t;
766typedef uint64_t of_wc_bmap_t;
767typedef uint64_t of_match_bmap_t;
768
769#define MEMMOVE(dest, src, bytes) memmove(dest, src, bytes)
770#define MEMSET(dest, val, bytes) memset(dest, val, bytes)
771#define MEMCPY(dest, src, bytes) memcpy(dest, src, bytes)
772#define MEMCMP(a, b, bytes) memcmp(a, b, bytes)
773#define MALLOC(bytes) malloc(bytes)
774#define FREE(ptr) free(ptr)
775
776/** Try an operation and return on failure. */
777#define OF_TRY(op) do { \\
778 int _rv; \\
779 if ((_rv = (op)) < 0) { \\
780 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
781 return _rv; \\
782 } \\
783 } while (0)
784
785/* The extent of an OF match object is determined by its length field, but
786 * aligned to 8 bytes
787 */
788
789#define OF_MATCH_BYTES(length) (((length) + 7) & 0xfff8)
790
791#if __BYTE_ORDER == __BIG_ENDIAN
792#define U16_NTOH(val) (val)
793#define U32_NTOH(val) (val)
794#define U64_NTOH(val) (val)
795#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
796#define U16_HTON(val) (val)
797#define U32_HTON(val) (val)
798#define U64_HTON(val) (val)
799#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
800#else /* Little Endian */
801#define U16_NTOH(val) (((val) >> 8) | ((val) << 8))
802#define U32_NTOH(val) ((((val) & 0xff000000) >> 24) | \\
803 (((val) & 0x00ff0000) >> 8) | \\
804 (((val) & 0x0000ff00) << 8) | \\
805 (((val) & 0x000000ff) << 24))
806#define U64_NTOH(val) ((((val) & 0xff00000000000000LL) >> 56) | \\
807 (((val) & 0x00ff000000000000LL) >> 40) | \\
808 (((val) & 0x0000ff0000000000LL) >> 24) | \\
809 (((val) & 0x000000ff00000000LL) >> 8) | \\
810 (((val) & 0x00000000ff000000LL) << 8) | \\
811 (((val) & 0x0000000000ff0000LL) << 24) | \\
812 (((val) & 0x000000000000ff00LL) << 40) | \\
813 (((val) & 0x00000000000000ffLL) << 56))
814#define IPV6_NTOH(dst, src) /* NOTE different syntax; currently no-op */
815#define U16_HTON(val) U16_NTOH(val)
816#define U32_HTON(val) U32_NTOH(val)
817#define U64_HTON(val) U64_NTOH(val)
818#define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
819#endif
820
821/****************************************************************
822 *
823 * The following are internal definitions used by the automatically
824 * generated code. Users should not reference these definitions
825 * as they may change between versions of this code
826 *
827 ****************************************************************/
828
829#define OF_MESSAGE_IN_MATCH_POINTER(obj) \\
830 (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
831#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
832#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
833 (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
834
835#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
836 (FIXED_LEN + of_message_out_actions_len_get(obj))
837
838""")
839
840def external_h_top_matter(out, name):
841 """
842 Generate top matter for external header file
843
844 @param name The name of the output file
845 @param out The output file object
846 """
847 common_top_matter(out, name)
848 out.write("""
849#include <loci/loci_base.h>
850#include <loci/of_message.h>
851#include <loci/of_match.h>
852#include <loci/of_object.h>
853#include <loci/of_wire_buf.h>
854
855/****************************************************************
856 *
857 * This file is divided into the following sections.
858 *
859 * A few object specific macros
860 * Class typedefs (no struct definitions)
861 * Per-data type accessor function typedefs
862 * Per-class new/delete function typedefs
863 * Per-class static delete functions
864 * Per-class, per-member accessor declarations
865 * Per-class structure definitions
866 * Generic union (inheritance) definitions
867 * Pointer set function declarations
868 * Some special case macros
869 *
870 ****************************************************************/
871""")
872
873def gen_top_static_functions(out):
874 out.write("""
875
876#define _MAX_PARENT_ITERATIONS 4
877/**
878 * Iteratively update parent lengths thru hierarchy
879 * @param obj The object whose length is being updated
880 * @param delta The difference between the current and new lengths
881 *
882 * Note that this includes updating the object itself. It will
883 * iterate thru parents.
884 *
885 * Assumes delta > 0.
886 */
887static inline void
888of_object_parent_length_update(of_object_t *obj, int delta)
889{
Rich Laneed79e0d2013-03-26 14:30:31 -0700890#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700891 int count = 0;
892 of_wire_buffer_t *wbuf; /* For debug asserts only */
Rich Laneed79e0d2013-03-26 14:30:31 -0700893#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700894
895 while (obj != NULL) {
896 ASSERT(count++ < _MAX_PARENT_ITERATIONS);
897 obj->length += delta;
898 if (obj->wire_length_set != NULL) {
899 obj->wire_length_set(obj, obj->length);
900 }
Rich Laneed79e0d2013-03-26 14:30:31 -0700901#ifndef NDEBUG
Rich Lanea06d0c32013-03-25 08:52:03 -0700902 wbuf = obj->wire_object.wbuf;
Rich Laneed79e0d2013-03-26 14:30:31 -0700903#endif
Rich Lanea06d0c32013-03-25 08:52:03 -0700904
905 /* Asserts for wire length checking */
906 ASSERT(obj->length + obj->wire_object.obj_offset <=
907 WBUF_CURRENT_BYTES(wbuf));
908 if (obj->parent == NULL) {
909 ASSERT(obj->length + obj->wire_object.obj_offset ==
910 WBUF_CURRENT_BYTES(wbuf));
911 }
912
913 obj = obj->parent;
914 }
915}
916""")
917
918################################################################
919#
920################################################################
921
922def gen_version_enum(out):
923 """
924 Generate the enumerated type for versions in LoxiGen
925 @param out The file object to which to write the decs
926
927 This just uses the wire versions for now
928 """
929 out.write("""
930/**
931 * Enumeration of OpenFlow versions
932 *
933 * The wire protocol numbers are currently used for values of the corresponding
934 * version identifiers.
935 */
936typedef enum of_version_e {
937 OF_VERSION_UNKNOWN = 0,
938""")
939
940 is_first = True
941 max = 0
942 for v in of_g.wire_ver_map:
943 if is_first:
944 is_first = False
945 else:
946 out.write(",\n")
947 if v > max:
948 max = v
949 out.write(" %s = %d" % (of_g.wire_ver_map[v], v))
950
951 out.write("""
952} of_version_t;
953
954/**
955 * @brief Use this when declaring arrays indexed by wire version
956 */
957#define OF_VERSION_ARRAY_MAX %d
958""" % (max + 1))
Andreas Wundsam53256162013-05-02 14:05:53 -0700959
Rich Lanea06d0c32013-03-25 08:52:03 -0700960def gen_object_enum(out):
961 """
962 Generate the enumerated type for object identification in LoxiGen
963 @param out The file object to which to write the decs
964 """
965 out.write("""
966
967/**
968 * Enumeration of OpenFlow objects
969 *
970 * We enumerate the OpenFlow objects used internally. Note that some
971 * message types are determined both by an outer type (message type like
972 * stats_request) and an inner type (port stats). These are different
973 * messages in ofC.
974 *
975 * These values are for internal use only. They will change with
976 * different versions of ofC.
977 */
978
979typedef enum of_object_id_e {
980 /* Root object type */
981 OF_OBJECT_INVALID = -1, /* "invalid" return value for mappings */
982 OF_OBJECT = 0, /* Generic, untyped object */
983
984 /* OpenFlow message objects */
985""")
986 last = 0
987 msg_count = 0
988 for cls in of_g.ordered_messages:
989 out.write(" %s = %d,\n" % (enum_name(cls),
990 of_g.unified[cls]["object_id"]))
991 msg_count = of_g.unified[cls]["object_id"] + 1
992
993 out.write("\n /* Non-message objects */\n")
994 for cls in of_g.ordered_non_messages:
995 out.write(" %s = %d,\n" % (enum_name(cls),
996 of_g.unified[cls]["object_id"]))
997 last = of_g.unified[cls]["object_id"]
998 out.write("\n /* List objects */\n")
999 for cls in of_g.ordered_list_objects:
1000 out.write(" %s = %d,\n" % (enum_name(cls),
1001 of_g.unified[cls]["object_id"]))
1002 last = of_g.unified[cls]["object_id"]
1003
1004 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1005 for cls in of_g.ordered_pseudo_objects:
1006 out.write(" %s = %d,\n" % (enum_name(cls),
1007 of_g.unified[cls]["object_id"]))
1008 last = of_g.unified[cls]["object_id"]
1009
1010 out.write("""
1011 OF_OBJECT_COUNT = %d
1012} of_object_id_t;
1013
Rich Laneb157b0f2013-03-27 13:55:28 -07001014extern const char *const of_object_id_str[];
Rich Lanea06d0c32013-03-25 08:52:03 -07001015
1016#define OF_MESSAGE_OBJECT_COUNT %d
1017""" % ((last + 1), msg_count))
1018
1019 # Generate object type range checking for inheritance classes
1020
1021 # @fixme These should be determined algorithmicly
1022 out.write("""
1023/*
1024 * Macros to check if an object ID is within an inheritance class range
1025 */
1026""")
1027 # Alphabetical order for 'last'
1028 last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
1029 of_oxm="OF_OXM_VLAN_VID_MASKED",
1030 of_instruction="OF_INSTRUCTION_WRITE_METADATA",
1031 of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
1032 of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
1033 # @FIXME add meter_band ?
1034 )
1035 for cls, last in last_ids.items():
1036 out.write("""
1037#define %(enum)s_FIRST_ID (%(enum)s + 1)
1038#define %(enum)s_LAST_ID %(last)s
1039#define %(enum)s_VALID_ID(id) \\
1040 ((id) >= %(enum)s_FIRST_ID && \\
1041 (id) <= %(enum)s_LAST_ID)
1042""" % dict(enum=enum_name(cls), last=last))
1043 out.write("""
1044/**
1045 * Function to check a wire ID
1046 * @param object_id The ID to check
1047 * @param base_object_id The inheritance parent, if applicable
1048 * @returns boolean: If base_object_id is an inheritance class, check if
1049 * object_id is valid as a subclass. Otherwise return 1.
1050 *
1051 * Note: Could check that object_id == base_object_id in the
1052 * second case.
1053 */
1054static inline int
1055of_wire_id_valid(int object_id, int base_object_id) {
1056 switch (base_object_id) {
1057 case OF_ACTION:
1058 return OF_ACTION_VALID_ID(object_id);
1059 case OF_OXM:
1060 return OF_OXM_VALID_ID(object_id);
1061 case OF_QUEUE_PROP:
1062 return OF_QUEUE_PROP_VALID_ID(object_id);
1063 case OF_TABLE_FEATURE_PROP:
1064 return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
1065 case OF_INSTRUCTION:
1066 return OF_INSTRUCTION_VALID_ID(object_id);
1067 default:
1068 break;
1069 }
1070 return 1;
1071}
1072""")
1073
1074def gen_object_enum_str(out):
Rich Laneb157b0f2013-03-27 13:55:28 -07001075 out.write("\nconst char *const of_object_id_str[] = {\n")
Rich Lanea06d0c32013-03-25 08:52:03 -07001076 out.write(" \"of_object\",\n")
1077 for cls in of_g.ordered_messages:
1078 out.write(" \"%s\",\n" % cls)
1079 out.write("\n /* Non-message objects */\n")
1080 for cls in of_g.ordered_non_messages:
1081 out.write(" \"%s\",\n" % cls)
1082 out.write("\n /* List objects */\n")
1083 for cls in of_g.ordered_list_objects:
1084 out.write(" \"%s\",\n" % cls)
1085 out.write("\n /* Generic stats request/reply types; pseudo objects */\n")
1086 for cls in of_g.ordered_pseudo_objects:
1087 out.write(" \"%s\",\n" % cls)
1088 out.write("\n \"of_unknown_object\"\n};\n")
1089
1090 # We'll do version strings while we're at it
1091 out.write("""
Rich Laneb157b0f2013-03-27 13:55:28 -07001092 const char *const of_version_str[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07001093 "Unknown OpenFlow Version",
1094 "OpenFlow-1.0",
1095 "OpenFlow-1.1",
1096 "OpenFlow-1.2"
1097};
1098
1099const of_mac_addr_t of_mac_addr_all_ones = {
1100 {
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1102 }
1103};
1104/* Just to be explicit; static duration vars are init'd to 0 */
1105const of_mac_addr_t of_mac_addr_all_zeros = {
1106 {
1107 0, 0, 0, 0, 0, 0
1108 }
1109};
1110
1111const of_ipv6_t of_ipv6_all_ones = {
1112 {
1113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1115 }
1116};
1117/* Just to be explicit; static duration vars are init'd to 0 */
1118const of_ipv6_t of_ipv6_all_zeros = {
1119 {
1120 0, 0, 0, 0, 0, 0, 0, 0,
1121 0, 0, 0, 0, 0, 0, 0, 0
1122 }
1123};
1124
1125/** @var of_error_strings
1126 * The error string map; use abs value to index
1127 */
Rich Laneb157b0f2013-03-27 13:55:28 -07001128const char *const of_error_strings[] = { OF_ERROR_STRINGS };
Rich Lanea06d0c32013-03-25 08:52:03 -07001129""")
1130
1131################################################################
1132#
1133# Internal Utility Functions
1134#
1135################################################################
1136
1137
1138def acc_name(cls, m_name):
1139 """
1140 Generate the root name of an accessor function for typedef
1141 @param cls The class name
1142 @param m_name The member name
1143 """
1144 (m_type, get_rv) = get_acc_rv(cls, m_name)
1145 return "%s_%s" % (cls, m_type)
1146
1147def get_acc_rv(cls, m_name):
1148 """
1149 Determine the data type and return type for a get accessor.
1150
1151 The return type may be "void" or it may be the accessor type
1152 depending on the system configuration and on the data type.
1153
1154 @param cls The class name
1155 @param m_name The member name
1156 @return A pair (m_type, rv) where m_type is the unified type of the
1157 member and rv is the get_accessor return type
1158 """
1159 member = of_g.unified[cls]["union"][m_name]
1160 m_type = member["m_type"]
1161 rv = "int"
1162 if member_returns_val(cls, m_name):
1163 rv = m_type
1164 if m_type[-2:] == "_t":
1165 m_type = m_type[:-2]
1166
1167 return (m_type, rv)
1168
1169def param_list(cls, m_name, a_type):
1170 """
1171 Generate the parameter list (no parens) for an a_type accessor
1172 @param cls The class name
1173 @param m_name The member name
1174 @param a_type One of "set" or "get" or TBD
1175 """
1176 member = of_g.unified[cls]["union"][m_name]
1177 m_type = member["m_type"]
1178 params = ["%s_t *obj" % cls]
1179 if a_type == "set":
1180 if loxi_utils.type_is_scalar(m_type):
1181 params.append("%s %s" % (m_type, m_name))
1182 else:
1183 params.append("%s *%s" % (m_type, m_name))
1184 elif a_type in ["get", "bind"]:
1185 params.append("%s *%s" % (m_type, m_name))
1186 else:
1187 debug("Class %s, name %s Bad param list a_type: %s" %
1188 (cls, m_name, a_type))
1189 sys.exit(1)
1190 return params
1191
1192def typed_function_base(cls, m_name):
1193 """
1194 Generate the core name for accessors based on the type
1195 @param cls The class name
1196 @param m_name The member name
1197 """
1198 (m_type, get_rv) = get_acc_rv(cls, m_name)
1199 return "%s_%s" % (cls, m_type)
1200
1201def member_function_base(cls, m_name):
1202 """
1203 Generate the core name for accessors based on the member name
1204 @param cls The class name
1205 @param m_name The member name
1206 """
1207 return "%s_%s" % (cls, m_name)
1208
1209def field_ver_get(cls, m_name):
1210 """
1211 Generate a dict, indexed by wire version, giving a pair (type, offset)
1212
1213 @param cls The class name
1214 @param m_name The name of the class member
1215
1216 If offset is not known for m_name, the type
1217 A dict is used for more convenient indexing.
1218 """
1219 result = {}
1220
1221 for ver in of_g.unified[cls]:
1222 if type(ver) == type(0): # It's a version
1223 if "use_version" in of_g.unified[cls][ver]: # deref version ref
1224 ref_ver = of_g.unified[cls][ver]["use_version"]
1225 members = of_g.unified[cls][ref_ver]["members"]
1226 else:
1227 members = of_g.unified[cls][ver]["members"]
1228 idx = loxi_utils.member_to_index(m_name, members)
1229 if (idx < 0):
1230 continue # Member not in this version
1231 m_type = members[idx]["m_type"]
1232 offset = members[idx]["offset"]
1233
1234 # If m_type is mixed, get wire version type from global data
1235 if m_type in of_g.of_mixed_types and \
1236 ver in of_g.of_mixed_types[m_type]:
1237 m_type = of_g.of_mixed_types[m_type][ver]
1238
1239 # add version to result list
1240 result[ver] = (m_type, offset)
1241
1242 return result
1243
1244def v3_match_offset_get(cls):
1245 """
Andreas Wundsam53256162013-05-02 14:05:53 -07001246 Return the offset of an OF 1.2 match in an object if it has such;
Rich Lanea06d0c32013-03-25 08:52:03 -07001247 otherwise return -1
1248 """
1249 result = field_ver_get(cls, "match")
1250 if of_g.VERSION_1_2 in result:
1251 if result[of_g.VERSION_1_2][0] == "of_match_v3_t":
1252 return result[of_g.VERSION_1_2][1]
1253 return -1
1254
1255################################################################
1256#
1257# OpenFlow Object Definitions
1258#
1259################################################################
1260
1261
1262def gen_of_object_defs(out):
1263 """
1264 Generate low level of_object core operations
1265 @param out The file for output, already open
1266 """
1267
1268def gen_generics(out):
1269 for (cls, subclasses) in type_maps.inheritance_map.items():
1270 out.write("""
1271/**
1272 * Inheritance super class for %(cls)s
1273 *
1274 * This class is the union of %(cls)s classes. You can refer
1275 * to it untyped by refering to the member 'header' whose structure
1276 * is common across all sub-classes.
1277 */
1278
1279union %(cls)s_u {
1280 %(cls)s_header_t header; /* Generic instance */
1281""" % dict(cls=cls))
1282 for subcls in sorted(subclasses):
1283 out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
1284 out.write("};\n")
1285
1286def gen_struct_typedefs(out):
1287 """
1288 Generate typedefs for all struct objects
1289 @param out The file for output, already open
1290 """
1291
1292 out.write("\n/* LOCI inheritance parent typedefs */\n")
1293 for cls in type_maps.inheritance_map:
1294 out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
1295 out.write("\n/* LOCI object typedefs */\n")
1296 for cls in of_g.standard_class_order:
1297 if cls in type_maps.inheritance_map:
1298 continue
1299 if config_check("gen_fn_ptrs"):
1300 out.write("typedef struct %(cls)s_s %(cls)s_t;\n" % dict(cls=cls))
1301 else:
1302 template = "typedef of_object_t %(cls)s_t;\n"
1303 out.write(template % dict(cls=cls))
1304
1305 out.write("""
1306/****************************************************************
1307 *
1308 * Additional of_object defines
1309 * These are needed for some static inline ops, so we put them here.
1310 *
1311 ****************************************************************/
1312
1313/* Delete an OpenFlow object without reference to its type */
1314extern void of_object_delete(of_object_t *obj);
1315
1316""")
1317
1318def gen_generic_union(out):
1319 """
1320 Generate the generic union object composing all LOCI objects
1321
1322 @param out The file to which to write the decs
1323 """
1324 out.write("""
1325/**
1326 * The common LOCI object is a union of all possible objects.
1327 */
1328union of_generic_u {
1329 of_object_t object; /* Common base class with fundamental accessors */
1330
1331 /* Message objects */
1332""")
1333 for cls in of_g.ordered_messages:
1334 out.write(" %s_t %s;\n" % (cls, cls))
1335 out.write("\n /* Non-message composite objects */\n")
1336 for cls in of_g.ordered_non_messages:
1337 if cls in type_maps.inheritance_map:
1338 continue
1339 out.write(" %s_t %s;\n" % (cls, cls))
1340 out.write("\n /* List objects */\n")
1341 for cls in of_g.ordered_list_objects:
1342 out.write(" %s_t %s;\n" % (cls, cls))
1343 out.write("};\n")
1344
1345def gen_common_struct_definitions(out):
1346 out.write("""
1347/****************************************************************
1348 *
1349 * Unified structure definitions
1350 *
1351 ****************************************************************/
1352
1353struct of_object_s {
1354 /* Common members */
1355%(common)s
1356};
1357""" % dict(common=of_g.base_object_members))
1358
1359def gen_flow_add_setup_function_declarations(out):
1360 """
1361 Add the declarations for functions that can be initialized
1362 by a flow add. These are defined external to LOXI.
1363 """
1364
1365 out.write("""
1366/****************************************************************
1367 * Functions for objects that can be initialized by a flow add message.
1368 * These are defined in a non-autogenerated file
1369 ****************************************************************/
1370
1371/**
1372 * @brief Set up a flow removed message from the original add
1373 * @param obj The flow removed message being updated
1374 * @param flow_add The flow_add message to use
1375 *
1376 * Initialize the following fields of obj to be identical
1377 * to what was originally on the wire from the flow_add object:
1378 * match
1379 * cookie
1380 * priority
1381 * idle_timeout
1382 * hard_timeout
1383 *
1384 */
1385
1386extern int
1387of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
1388 of_flow_add_t *flow_add);
1389
1390
1391/**
1392 * @brief Set up the packet in match structure from the original add
1393 * @param obj The packet in message being updated
1394 * @param flow_add The flow_add message to use
1395 * @returns Indigo error code. Does not return a version error if
1396 * the version does not require initializing obj.
1397 *
1398 * Initialize the match member of obj to be identical to what was originally
1399 * on the wire from the flow_add object. If applicable, the table ID is also
1400 * initialized from the flow_add object.
1401 *
1402 * This API applies to 1.2 and later only.
1403 */
1404
1405extern int
1406of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
1407 of_flow_add_t *flow_add);
1408
1409
1410/**
1411 * @brief Set up the flow stats entry from the original add
1412 * @param obj The packet in message being updated
1413 * @param flow_add The flow_add message to use
1414 * @param effects Optional actions or instructions; see below.
1415 *
1416 * Initialize the following fields of obj to be identical
1417 * to what was originally on the wire from the flow_add object:
1418 * match
1419 * actions/instructions (effects)
1420 * cookie
1421 * priority
1422 * idle_timeout
1423 * hard_timeout
1424 *
Andreas Wundsam53256162013-05-02 14:05:53 -07001425 * Note that the actions/instructions of a flow may be modified by a
Rich Lanea06d0c32013-03-25 08:52:03 -07001426 * subsequent flow modify message. To facilitate implementations,
1427 * the "effects" parameter is provided. If effects is NULL, the
1428 * actions/instructions are taken from the flow_add message.
1429 * Otherwise, effects is coerced to the proper type (actions or
1430 * instructions) and used to init obj.
1431 */
1432
1433extern int
1434of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
1435 of_flow_add_t *flow_add,
1436 of_object_t *effects);
1437""")
1438
1439def gen_struct_definitions(out):
1440 """
1441 Generate the declaration of all of_ C structures
1442
1443 @param out The file to which to write the decs
1444 """
1445
1446 # This should only get called if gen_fn_ptr is true in code_gen_config
1447 if not config_check("gen_fn_ptrs"):
1448 debug("Error: gen_struct_defs called, but no fn ptrs set")
1449 return
1450
1451 for cls in of_g.standard_class_order:
1452 if cls in type_maps.inheritance_map:
1453 continue # These are generated elsewhere
1454 note = ""
1455 if loxi_utils.class_is_message(cls):
1456 note = " /* Class is message */"
1457 out.write("struct %s_s {%s\n" % (cls, note))
1458 out.write(""" /* Common members */
1459%s
1460 /* Class specific members */
1461""" % of_g.base_object_members)
1462 if loxi_utils.class_is_list(cls):
1463 out.write("""
1464 %(cls)s_first_f first;
1465 %(cls)s_next_f next;
1466 %(cls)s_append_bind_f append_bind;
1467 %(cls)s_append_f append;
1468};
1469
1470""" % {"cls": cls})
1471 continue # All done with list object
1472
1473 # Else, not a list instance; add accessors for all data members
1474 for m_name in of_g.ordered_members[cls]:
1475 if m_name in of_g.skip_members:
1476 # These members (length, etc) are handled internally
1477 continue
1478 f_name = acc_name(cls, m_name)
1479 out.write(" %s_get_f %s;\n" % (f_name, m_name + "_get"))
1480 out.write(" %s_set_f %s;\n" % (f_name, m_name + "_set"))
1481 out.write("};\n\n")
1482
1483
1484################################################################
1485#
1486# List accessor code generation
1487#
1488# Currently these all implement copy on read semantics
1489#
1490################################################################
1491
1492def init_call(e_type, obj, ver, length, cw):
1493 """
1494 Generate the init call given the strings for params
1495 """
1496 hdr = "" # If inheritance type, coerce to hdr object
1497 obj_name = obj
1498 if e_type in type_maps.inheritance_map:
1499 hdr = "_header"
1500 obj_name = "(%s_header_t *)" % e_type + obj
1501
1502 return """\
1503%(e_type)s%(hdr)s_init(%(obj_name)s,
1504 %(ver)s, %(length)s, %(cw)s)\
1505""" % dict(e_type=e_type, hdr=hdr, obj_name=obj_name, ver=ver,
1506 length=length, cw=cw)
1507
1508def gen_list_first(out, cls, e_type):
1509 """
1510 Generate the body of a list_first operation
1511 @param cls The class name for which code is being generated
1512 @param e_type The element type of the list
1513 @param out The file to which to write
1514 """
1515 i_call = init_call(e_type, "obj", "list->version", "0", "1")
1516 if e_type in type_maps.inheritance_map:
1517 len_str = "obj->header.length"
1518 else:
1519 len_str = "obj->length"
1520
1521 out.write("""
1522/**
1523 * Associate an iterator with a list
1524 * @param list The list to iterate over
1525 * @param obj The list entry iteration pointer
1526 * @return OF_ERROR_RANGE if the list is empty (end of list)
1527 *
1528 * The obj instance is completely initialized. The caller is responsible
1529 * for cleaning up any wire buffers associated with obj before this call
1530 */
1531
1532int
1533%(cls)s_first(%(cls)s_t *list,
1534 %(e_type)s_t *obj)
1535{
1536 int rv;
1537
1538 %(i_call)s;
1539 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1540 return rv;
1541 }
1542""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1543
1544 # Special case flow_stats_entry lists
1545
1546 out.write("""
1547 of_object_wire_init((of_object_t *) obj, %(u_type)s,
1548 list->length);
1549 if (%(len_str)s == 0) {
1550 return OF_ERROR_PARSE;
1551 }
1552
1553 return rv;
1554}
1555""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1556
1557
1558def gen_bind(out, cls, m_name, m_type):
1559 """
1560 Generate the body of a bind function
1561 @param out The file to which to write
1562 @param cls The class name for which code is being generated
1563 @param m_name The name of the data member
1564 @param m_type The type of the data member
1565 """
1566
1567 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1568
1569 i_call = init_call(e_type, "child", "parent->version", "0", "1")
1570
1571 out.write("""
1572/**
1573 * Bind the child object to the parent object for read processing
1574 * @param parent The parent object
1575 * @param child The child object
1576 *
1577 * The child obj instance is completely initialized.
1578 */
1579
1580int
1581%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
1582 %(e_type)s_t *child)
1583{
1584 int rv;
1585
1586 %(i_call)s;
1587
1588 /* Derive offset and length of child in parent */
Andreas Wundsam53256162013-05-02 14:05:53 -07001589 OF_TRY(of_object_child_attach(parent, child,
Rich Lanea06d0c32013-03-25 08:52:03 -07001590 if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
1591 return rv;
1592 }
1593""" % dict(cls=cls, e_type=e_type, i_call=i_call))
1594
1595 # Special case flow_stats_entry lists
1596
1597 out.write("""
1598 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1599 list->length);
1600 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1601 return OF_ERROR_PARSE;
1602 }
1603
1604 return rv;
1605}
1606""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1607
1608
1609def gen_list_next(out, cls, e_type):
1610 """
1611 Generate the body of a list_next operation
1612 @param cls The class name for which code is being generated
1613 @param e_type The element type of the list
1614 @param out The file to which to write
1615 """
1616
1617 if e_type in type_maps.inheritance_map:
1618 len_str = "obj->header.length"
1619 else:
1620 len_str = "obj->length"
Andreas Wundsam53256162013-05-02 14:05:53 -07001621
Rich Lanea06d0c32013-03-25 08:52:03 -07001622 out.write("""
1623/**
1624 * Advance an iterator to the next element in a list
1625 * @param list The list being iterated
1626 * @param obj The list entry iteration pointer
1627 * @return OF_ERROR_RANGE if already at the last entry on the list
1628 *
1629 */
1630
1631int
1632%(cls)s_next(%(cls)s_t *list,
1633 %(e_type)s_t *obj)
1634{
1635 int rv;
1636
1637 if ((rv = of_list_next((of_object_t *)list, (of_object_t *)obj)) < 0) {
1638 return rv;
1639 }
1640
1641 rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
1642 list->length);
1643
1644 if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
1645 return OF_ERROR_PARSE;
1646 }
1647
1648 return rv;
1649}
1650""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
1651
1652def gen_list_append(out, cls, e_type):
1653 """
1654 Generate the body of a list append functions
1655 @param cls The class name for which code is being generated
1656 @param e_type The element type of the list
1657 @param out The file to which to write
1658 """
1659
1660 out.write("""
1661/**
1662 * Set up to append an object of type %(e_type)s to an %(cls)s.
1663 * @param list The list that is prepared for append
1664 * @param obj Pointer to object to hold data to append
1665 *
1666 * The obj instance is completely initialized. The caller is responsible
1667 * for cleaning up any wire buffers associated with obj before this call.
1668 *
1669 * See the generic documentation for of_list_append_bind.
1670 */
1671
1672int
1673%(cls)s_append_bind(%(cls)s_t *list,
1674 %(e_type)s_t *obj)
1675{
1676 return of_list_append_bind((of_object_t *)list, (of_object_t *)obj);
1677}
1678
1679/**
1680 * Append an item to a %(cls)s list.
1681 *
1682 * This copies data from item and leaves item untouched.
1683 *
1684 * See the generic documentation for of_list_append.
1685 */
1686
1687int
1688%(cls)s_append(%(cls)s_t *list,
1689 %(e_type)s_t *item)
1690{
1691 return of_list_append((of_object_t *)list, (of_object_t *)item);
1692}
1693
1694""" % dict(cls=cls, e_type=e_type))
1695
1696def gen_list_accessors(out, cls):
1697 e_type = loxi_utils.list_to_entry_type(cls)
1698 gen_list_first(out, cls, e_type)
1699 gen_list_next(out, cls, e_type)
1700 gen_list_append(out, cls, e_type)
1701
1702################################################################
1703#
1704# Accessor Functions
1705#
1706################################################################
1707
Andreas Wundsam53256162013-05-02 14:05:53 -07001708
Rich Lanea06d0c32013-03-25 08:52:03 -07001709def gen_accessor_declarations(out):
1710 """
1711 Generate the declaration of each version independent accessor
1712
1713 @param out The file to which to write the decs
1714 """
1715
1716 out.write("""
1717/****************************************************************
1718 *
1719 * Unified, per-member accessor function declarations
1720 *
1721 ****************************************************************/
1722""")
1723 for cls in of_g.standard_class_order:
1724 if cls in type_maps.inheritance_map:
1725 continue
1726 out.write("\n/* Unified accessor functions for %s */\n" % cls)
1727 for m_name in of_g.ordered_members[cls]:
1728 if m_name in of_g.skip_members:
1729 continue
1730 m_type = loxi_utils.member_base_type(cls, m_name)
1731 base_name = "%s_%s" % (cls, m_name)
1732 gparams = ",\n ".join(param_list(cls, m_name, "get"))
1733 get_ret_type = accessor_return_type("get", m_type)
1734 sparams = ",\n ".join(param_list(cls, m_name, "set"))
1735 set_ret_type = accessor_return_type("set", m_type)
1736 bparams = ",\n ".join(param_list(cls, m_name, "bind"))
1737 bind_ret_type = accessor_return_type("bind", m_type)
1738
1739 if loxi_utils.type_is_of_object(m_type):
1740 # Generate bind accessors, but not get accessor
1741 out.write("""
1742extern %(set_ret_type)s %(base_name)s_set(
1743 %(sparams)s);
1744extern %(bind_ret_type)s %(base_name)s_bind(
1745 %(bparams)s);
1746extern %(m_type)s *%(cls)s_%(m_name)s_get(
1747 %(cls)s_t *obj);
1748""" % dict(base_name=base_name, sparams=sparams, bparams=bparams,
1749 m_name=m_name, m_type=m_type, cls=cls,
1750 set_ret_type=set_ret_type, bind_ret_type=bind_ret_type))
1751 else:
1752 out.write("""
1753extern %(set_ret_type)s %(base_name)s_set(
1754 %(sparams)s);
1755extern %(get_ret_type)s %(base_name)s_get(
1756 %(gparams)s);
1757""" % dict(base_name=base_name, gparams=gparams, sparams=sparams,
1758 get_ret_type=get_ret_type, set_ret_type=set_ret_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001759
Rich Lanea06d0c32013-03-25 08:52:03 -07001760 if loxi_utils.class_is_list(cls):
1761 e_type = loxi_utils.list_to_entry_type(cls)
1762 out.write("""
1763extern int %(cls)s_first(
1764 %(cls)s_t *list, %(e_type)s_t *obj);
1765extern int %(cls)s_next(
1766 %(cls)s_t *list, %(e_type)s_t *obj);
1767extern int %(cls)s_append_bind(
1768 %(cls)s_t *list, %(e_type)s_t *obj);
1769extern int %(cls)s_append(
1770 %(cls)s_t *list, %(e_type)s_t *obj);
1771
1772/**
1773 * Iteration macro for list of type %(cls)s
1774 * @param list Pointer to the list being iterated over of
1775 * type %(cls)s
1776 * @param elt Pointer to an element of type %(e_type)s
1777 * @param rv On exiting the loop will have the value OF_ERROR_RANGE.
1778 */
1779#define %(u_cls)s_ITER(list, elt, rv) \\
1780 for ((rv) = %(cls)s_first((list), (elt)); \\
1781 (rv) == OF_ERROR_NONE; \\
1782 (rv) = %(cls)s_next((list), (elt)))
1783""" % dict(u_cls=cls.upper(), cls=cls, e_type=e_type))
1784
1785
1786def wire_accessor(m_type, a_type):
1787 """
1788 Returns the name of the a_type accessor for low level wire buff offset
1789 @param m_type The member type
1790 @param a_type The accessor type (set or get)
1791 """
1792 # Strip off _t if present
1793 if m_type in of_g.of_base_types:
1794 m_type = of_g.of_base_types[m_type]["short_name"]
1795 if m_type in of_g.of_mixed_types:
1796 m_type = of_g.of_mixed_types[m_type]["short_name"]
1797 if m_type[-2:] == "_t":
1798 m_type = m_type[:-2]
1799 if m_type == "octets":
1800 m_type = "octets_data"
1801 return "of_wire_buffer_%s_%s" % (m_type, a_type)
1802
1803def get_len_macro(cls, m_type, version):
1804 """
1805 Get the length macro for m_type in cls
1806 """
1807 if m_type.find("of_match") == 0:
1808 return "_WIRE_MATCH_PADDED_LEN(obj, offset)"
1809 if m_type.find("of_list_oxm") == 0:
1810 return "wire_match_len(obj, 0) - 4"
1811 if loxi_utils.class_is_tlv16(m_type):
1812 return "_TLV16_LEN(obj, offset)"
1813 if cls == "of_packet_out" and m_type == "of_list_action_t":
1814 return "_PACKET_OUT_ACTION_LEN(obj)"
1815 # Default is everything to the end of the object
1816 return "_END_LEN(obj, offset)"
1817
1818def gen_accessor_offsets(out, cls, m_name, version, a_type, m_type, offset):
1819 """
1820 Generate the sub-object offset and length calculations for accessors
1821 @param out File being written
1822 @param m_name Name of member
1823 @param version Wire version being processed
1824 @param a_type The accessor type (set or get)
1825 @param m_type The original member type
1826 @param offset The offset of the object or -1 if not fixed
1827 """
1828 # determine offset
1829 o_str = "%d" % offset # Default is fixed length
1830 if offset == -1:
1831 # There are currently 4 special cases for this
1832 # In general, get offset and length of predecessor
1833 if (loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions"):
1834 pass
1835 elif (cls == "of_flow_stats_entry" and m_name == "instructions"):
1836 pass
1837 elif (cls == "of_packet_in" and m_name == "data"):
1838 pass
1839 elif (cls == "of_packet_out" and m_name == "data"):
1840 pass
1841 else:
1842 debug("Error: Unknown member with offset == -1")
1843 debug(" cls %s, m_name %s, version %d" % (cls, m_name, version))
1844 sys.exit(1)
1845 o_str = "_%s_%s_OFFSET(obj)" % (cls.upper()[3:], m_name.upper())
1846
1847 out.write("""\
1848 offset = %s;
1849""" % o_str);
1850
1851 # This could be moved to main body but for version check
1852 if not loxi_utils.type_is_scalar(m_type):
1853 if loxi_utils.class_is_var_len(m_type[:-2], version) or \
1854 m_type == "of_match_t":
1855 len_macro = get_len_macro(cls, m_type, version)
1856 else:
1857 len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
1858 out.write(" cur_len = %s;\n" % len_macro)
1859 out.write(" break;\n")
1860
1861def length_of(m_type, version):
1862 """
1863 Return the length of a type based on the version
1864 """
1865 if m_type in of_g.of_mixed_types:
1866 m_type = of_g.of_mixed_types[m_type][version]
1867 if m_type in of_g.of_base_types:
1868 return of_g.of_base_types[m_type]["bytes"]
1869 if (m_type[:-2], version) in of_g.base_length:
1870 return of_g.base_length[(m_type[:-2], version)]
1871 print "Unknown length request", m_type, version
1872 sys.exit(1)
Andreas Wundsam53256162013-05-02 14:05:53 -07001873
Rich Lanea06d0c32013-03-25 08:52:03 -07001874
1875def gen_get_accessor_body(out, cls, m_type, m_name):
1876 """
1877 Generate the common operations for a get accessor
1878 """
1879 if loxi_utils.type_is_scalar(m_type):
1880 ver = "" # See if version required for scalar update
1881 if m_type in of_g.of_mixed_types:
1882 ver = "ver, "
1883 out.write("""\
1884 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s);
1885""" % dict(wa=wire_accessor(m_type, "get"), ver=ver, m_name=m_name))
1886
1887 if m_type == "of_port_no_t":
1888 out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
1889 elif m_type == "of_octets_t":
1890 out.write("""\
1891 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
1892 %(m_name)s->bytes = cur_len;
1893 %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
1894""" % dict(m_name=m_name))
1895 elif m_type == "of_match_t":
1896 out.write("""
1897 ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
1898 match_octets.bytes = cur_len;
1899 match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
1900 OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
1901""" % dict(m_name=m_name))
1902 else:
1903 out.write("""
1904 /* Initialize child */
1905 %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
1906 /* Attach to parent */
1907 %(m_name)s->parent = (of_object_t *)obj;
1908 %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
1909 %(m_name)s->wire_object.obj_offset = abs_offset;
1910 %(m_name)s->wire_object.owned = 0;
1911 %(m_name)s->length = cur_len;
1912""" % dict(m_type=m_type[:-2], m_name=m_name))
1913
1914
1915def gen_set_accessor_body(out, cls, m_type, m_name):
1916 """
1917 Generate the contents of a set accessor
1918 """
1919 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
1920 ver = "" # See if version required for scalar update
1921 if m_type in of_g.of_mixed_types:
1922 ver = "ver, "
1923 cur_len = "" # See if version required for scalar update
1924 if m_type == "of_octets_t":
1925 cur_len = ", cur_len"
1926 out.write("""\
1927 new_len = %(m_name)s->bytes;
1928 of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len));
1929""" % dict(m_name=m_name))
1930 out.write("""\
1931 %(wa)s(%(ver)swbuf, abs_offset, %(m_name)s%(cur_len)s);
1932""" % dict(wa=wire_accessor(m_type, "set"), ver=ver, cur_len=cur_len,
1933 m_name=m_name))
1934
1935 elif m_type == "of_match_t":
1936 out.write("""
1937 /* Match object */
1938 OF_TRY(of_match_serialize(ver, %(m_name)s, &match_octets));
1939 new_len = match_octets.bytes;
1940 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1941 match_octets.data, new_len);
1942 /* Free match serialized octets */
1943 FREE(match_octets.data);
1944""" % dict(m_name=m_name))
1945
1946 else: # Other object type
1947 out.write("\n /* LOCI object type */")
1948 # Need to special case OXM list
1949 out.write("""
1950 new_len = %(m_name)s->length;
1951 /* If underlying buffer already shared; nothing to do */
1952 if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
1953 of_wire_buffer_grow(wbuf, abs_offset + new_len);
1954 /* Verify that the offsets are correct */
1955 ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
1956 /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
1957 return %(ret_success)s;
1958 }
1959
1960 /* Otherwise, replace existing object in data buffer */
1961 of_wire_buffer_replace_data(wbuf, abs_offset, cur_len,
1962 OF_OBJECT_BUFFER_INDEX(%(m_name)s, 0), new_len);
1963""" % dict(m_name=m_name, ret_success=accessor_return_success("set", m_type)))
1964
1965 if not loxi_utils.type_is_scalar(m_type):
1966 if cls == "of_packet_out" and m_type == "of_list_action_t":
1967 out.write("""
1968 /* Special case for setting action lengths */
1969 _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
1970""" % dict(m_name=m_name))
1971 elif m_type not in ["of_match_t", "of_octets_t"]:
1972 out.write("""
1973 /* @fixme Shouldn't this precede copying value's data to buffer? */
1974 if (%(m_name)s->wire_length_set != NULL) {
1975 %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
1976 }
1977""" % dict(m_name=m_name))
1978 out.write("""
1979 /* Not scalar, update lengths if needed */
1980 delta = new_len - cur_len;
1981 if (delta != 0) {
1982 /* Update parent(s) */
1983 of_object_parent_length_update((of_object_t *)obj, delta);
1984 }
1985""")
1986
1987def obj_assert_check(cls):
1988 """
1989 The body of the assert check for an accessor
1990 We allow all versions of add/delete/modify to use the same accessors
1991 """
1992 if cls in ["of_flow_modify", "of_flow_modify_strict",
1993 "of_flow_delete", "of_flow_delete_strict",
1994 "of_flow_add"]:
1995 return "IS_FLOW_MOD_SUBTYPE(obj->object_id)"
1996 else:
1997 return "obj->object_id == %s" % cls.upper()
1998
1999def gen_of_object_get(out, cls, m_name, m_type):
2000 sub_cls = m_type[:-2]
2001 out.write("""
2002/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002003 * Create a copy of %(m_name)s into a new variable of type %(m_type)s from
Rich Lanea06d0c32013-03-25 08:52:03 -07002004 * a %(cls)s instance.
2005 *
2006 * @param obj Pointer to the source of type %(cls)s_t
2007 * @returns A pointer to a new instance of type %(m_type)s whose contents
2008 * match that of %(m_name)s from source
2009 * @returns NULL if an error occurs
2010 */
2011%(m_type)s *
2012%(cls)s_%(m_name)s_get(%(cls)s_t *obj) {
2013 %(m_type)s _%(m_name)s;
2014 %(m_type)s *_%(m_name)s_ptr;
2015
2016 %(cls)s_%(m_name)s_bind(obj, &_%(m_name)s);
2017 _%(m_name)s_ptr = (%(m_type)s *)of_object_dup(&_%(m_name)s);
2018 return _%(m_name)s_ptr;
2019}
2020""" % dict(m_name=m_name, m_type=m_type, cls=cls, sub_cls=sub_cls))
2021
2022def gen_unified_acc_body(out, cls, m_name, ver_type_map, a_type, m_type):
2023 """
2024 Generate the body of a set or get accessor function
2025
2026 @param out The file to which to write the decs
2027 @param cls The class name
2028 @param m_name The member name
2029 @param ver_type_map Maps (type, offset) pairs to a list of versions
2030 @param a_type The accessor type, set or get
2031 @param m_type The original member type
2032
2033 The type values in ver_type_map are now ignored as we've pushed down
2034 the type munging to the lower level.
2035
2036 This is unified because the version switch case processing is the
2037 same for both set and get
2038 """
2039 out.write("""{
2040 of_wire_buffer_t *wbuf;
2041 int offset = 0; /* Offset of value relative to the start obj */
2042 int abs_offset; /* Offset of value relative to start of wbuf */
2043 of_version_t ver;
2044""")
2045
2046 if not loxi_utils.type_is_scalar(m_type):
2047 out.write("""\
2048 int cur_len = 0; /* Current length of object data */
2049""")
2050 if a_type == "set":
2051 out.write("""\
2052 int new_len, delta; /* For set, need new length and delta */
2053""")
2054
2055 # For match, need octet string for set/get
2056 if m_type == "of_match_t":
2057 out.write("""\
2058 of_octets_t match_octets; /* Serialized string for match */
2059""")
2060
2061 out.write("""
2062 ASSERT(%(assert_str)s);
2063 ver = obj->version;
2064 wbuf = OF_OBJECT_TO_WBUF(obj);
2065 ASSERT(wbuf != NULL);
2066
2067 /* By version, determine offset and current length (where needed) */
2068 switch (ver) {
2069""" % dict(assert_str=obj_assert_check(cls)))
2070
2071 for first in sorted(ver_type_map):
2072 (prev_t, prev_o) = ver_type_map[first]
2073 prev_len = length_of(prev_t, first)
2074 prev = first
2075 out.write(" case %s:\n" % of_g.wire_ver_map[first])
2076 break
2077
2078 for next in sorted(ver_type_map):
2079 if next == first:
2080 continue
2081
2082 (t, o) = ver_type_map[next]
2083 cur_len = length_of(t, next)
2084 if o == prev_o and cur_len == prev_len:
2085 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2086 continue
2087 gen_accessor_offsets(out, cls, m_name, prev, a_type, m_type, prev_o)
2088 out.write(" case %s:\n" % of_g.wire_ver_map[next])
2089 (prev_t, prev_o, prev_len, prev) = (t, o, cur_len, next)
2090
2091 gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
2092 out.write("""\
2093 default:
2094 ASSERT(0);
2095 }
2096
2097 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
2098 ASSERT(abs_offset >= 0);
2099""")
2100 if not loxi_utils.type_is_scalar(m_type):
2101 out.write(" ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
2102
2103 # Now generate the common accessor code
2104 if a_type in ["get", "bind"]:
2105 gen_get_accessor_body(out, cls, m_type, m_name)
2106 else:
2107 gen_set_accessor_body(out, cls, m_type, m_name)
2108
2109 out.write("""
2110 OF_LENGTH_CHECK_ASSERT(obj);
2111
2112 return %s;
2113}
2114""" % accessor_return_success(a_type, m_type))
2115
2116def gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map):
2117 """
2118 For generating the bind call for OF sub-objects
2119 """
2120
2121 params = ",\n ".join(param_list(cls, m_name, "bind"))
2122 out.write("""
2123/**
2124 * Bind an object of type %(m_type)s to the parent of type %(cls)s for
2125 * member %(m_name)s
2126 * @param obj Pointer to an object of type %(cls)s.
2127 * @param %(m_name)s Pointer to the child object of type
2128 * %(m_type)s to be filled out.
2129 * \ingroup %(cls)s
2130 *
2131 * The parameter %(m_name)s is filled out to point to the same underlying
2132 * wire buffer as its parent.
2133 *
2134 */
2135""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2136
2137 ret_type = accessor_return_type("bind", m_type)
2138 out.write("%s\n%s_%s_bind(\n %s)\n" % (ret_type, cls, m_name, params))
2139 gen_unified_acc_body(out, cls, m_name, ver_type_map, "bind", m_type)
2140
2141def gen_get_accessor(out, cls, m_name, m_type, ver_type_map):
2142 """
2143 For generating the get call for non- OF sub-objects
2144 """
2145 params = ",\n ".join(param_list(cls, m_name, "get"))
2146 out.write("""
2147/**
2148 * Get %(m_name)s from an object of type %(cls)s.
2149 * @param obj Pointer to an object of type %(cls)s.
2150 * @param %(m_name)s Pointer to the child object of type
2151 * %(m_type)s to be filled out.
2152 *
2153 */
2154""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2155
2156 ret_type = accessor_return_type("get", m_type)
2157 out.write("%s\n%s_%s_get(\n %s)\n" % (ret_type, cls, m_name, params))
2158 gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
2159
Rich Lanece2e4642013-12-15 12:05:45 -08002160def gen_accessor_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002161 for m_name in of_g.ordered_members[cls]:
2162 if m_name in of_g.skip_members:
2163 continue
2164 m_type = loxi_utils.member_base_type(cls, m_name)
2165 ver_type_map = field_ver_get(cls, m_name)
2166
2167 # Generate get/bind pending on member type
2168 # FIXME: Does this do the right thing for match?
2169 if loxi_utils.type_is_of_object(m_type):
2170 gen_of_obj_bind(out, cls, m_name, m_type, ver_type_map)
2171 gen_of_object_get(out, cls, m_name, m_type)
2172 else:
2173 gen_get_accessor(out, cls, m_name, m_type, ver_type_map)
2174
2175 # Now generate set accessor for all objects
2176 params = ",\n ".join(param_list(cls, m_name, "set"))
2177 out.write("""
2178/**
2179 * Set %(m_name)s in an object of type %(cls)s.
2180 * @param obj Pointer to an object of type %(cls)s.
2181""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2182 if loxi_utils.type_is_scalar(m_type) or m_type == "of_octets_t":
2183 out.write("""\
2184 * @param %(m_name)s The value to write into the object
2185 */
2186""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2187 else:
2188 out.write("""\
2189 * @param %(m_name)s Pointer to the child of type %(m_type)s.
2190 *
2191 * If the child's wire buffer is the same as the parent's, then
2192 * nothing is done as the changes have already been registered in the
2193 * parent. Otherwise, the data in the child's wire buffer is inserted
2194 * into the parent's and the appropriate lengths are updated.
2195 */
2196""" % dict(m_name=m_name, cls=cls, m_type=m_type))
2197 ret_type = accessor_return_type("set", m_type)
2198 out.write("%s\n%s_%s_set(\n %s)\n" % (ret_type, cls, m_name, params))
2199 gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
2200
Rich Lanea06d0c32013-03-25 08:52:03 -07002201def gen_acc_pointer_typedefs(out):
2202 """
2203 Generate the function pointer typedefs for in-struct accessors
2204 @param out The file to which to write the typedefs
2205 """
2206
2207 out.write("""
2208/****************************************************************
2209 *
2210 * Accessor function pointer typedefs
2211 *
2212 ****************************************************************/
2213
2214/*
2215 * Generic accessors:
2216 *
2217 * Many objects have a length represented in the wire buffer
2218 * wire_length_get and wire_length_set access these values directly on the
2219 * wire.
2220 *
2221 * Many objects have a length represented in the wire buffer
2222 * wire_length_get and wire_length_set access these values directly on the
2223 * wire.
2224 *
2225 * FIXME: TBD if wire_length_set and wire_type_set are required.
2226 */
2227typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
2228typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
2229typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
Rich Lane92feca82013-12-10 15:57:13 -08002230typedef void (*of_wire_type_set_f)(of_object_t *obj);
Rich Lanea06d0c32013-03-25 08:52:03 -07002231""")
2232 # If not using function pointers in classes, don't gen typedefs below
2233 if not config_check("gen_fn_ptrs"):
2234 return
2235
2236 # For each class, for each type it uses, generate a typedef
2237 for cls in of_g.standard_class_order:
2238 if cls in type_maps.inheritance_map:
2239 continue
2240 out.write("\n/* Accessor function pointer typedefs for %s */\n" % cls)
2241 types_done = list()
2242 for m_name in of_g.ordered_members[cls]:
2243 (m_type, get_rv) = get_acc_rv(cls, m_name)
2244 if (m_type, get_rv) in types_done:
2245 continue
2246 types_done.append((m_type, get_rv))
2247 fn = "%s_%s" % (cls, m_type)
2248 params = ", ".join(param_list(cls, m_name, "get"))
2249 out.write("typedef int (*%s_get_f)(\n %s);\n" %
2250 (fn, params))
2251
2252 params = ", ".join(param_list(cls, m_name, "set"))
2253 out.write("typedef int (*%s_set_f)(\n %s);\n" %
2254 (fn, params))
2255 if loxi_utils.class_is_list(cls):
2256 obj_type = loxi_utils.list_to_entry_type(cls)
2257 out.write("""typedef int (*%(cls)s_first_f)(
2258 %(cls)s_t *list,
2259 %(obj_type)s_t *obj);
2260typedef int (*%(cls)s_next_f)(
2261 %(cls)s_t *list,
2262 %(obj_type)s_t *obj);
2263typedef int (*%(cls)s_append_bind_f)(
2264 %(cls)s_t *list,
2265 %(obj_type)s_t *obj);
2266typedef int (*%(cls)s_append_f)(
2267 %(cls)s_t *list,
2268 %(obj_type)s_t *obj);
2269""" % {"cls":cls, "obj_type":obj_type})
2270
2271# out.write("""
2272# typedef int (*%(cls)s_get_f)(
2273# %(cls)s_t *list,
2274# %(obj_type)s_t *obj, int index);
2275# typedef int (*%(cls)s_set_f)(
2276# %(cls)s_t *list,
2277# %(obj_type)s_t *obj, int index);
2278# typedef int (*%(cls)s_append_f)(
2279# %(cls)s_t *list,
2280# %(obj_type)s_t *obj, int index);
2281# typedef int (*%(cls)s_insert_f)(
2282# %(cls)s_t *list,
2283# %(obj_type)s_t *obj, int index);
2284# typedef int (*%(cls)s_remove_f)(
2285# %(cls)s_t *list,
2286# int index);
2287# """ % {"cls":cls, "obj_type":obj_type})
2288
2289################################################################
2290#
2291# New/Delete Function Definitions
2292#
2293################################################################
2294
2295
2296################################################################
2297# First, some utility functions for new/delete
2298################################################################
2299
2300def del_function_proto(cls):
2301 """
2302 Return the prototype for the delete operator for the given class
2303 @param cls The class name
2304 """
2305 fn = "void\n"
2306 return fn
2307
2308
2309def instantiate_fn_ptrs(cls, ilvl, out):
2310 """
2311 Generate the C code to instantiate function pointers for a class
2312 @param cls The class name
2313 @param ilvl The base indentation level
2314 @param out The file to which to write the functions
2315 """
2316 for m_name in of_g.ordered_members[cls]:
2317 if m_name in of_g.skip_members:
2318 continue
2319 out.write(" " * ilvl + "obj->%s_get = %s_%s_get;\n" %
2320 (m_name, cls, m_name))
2321 out.write(" " * ilvl + "obj->%s_set = %s_%s_set;\n" %
2322 (m_name, cls, m_name))
2323
2324################################################################
2325# Routines to generate the body of new/delete functions
2326################################################################
2327
2328def gen_init_fn_body(cls, out):
2329 """
2330 Generate function body for init function
2331 @param cls The class name for the function
2332 @param out The file to which to write
2333 """
2334 if cls in type_maps.inheritance_map:
2335 param = "obj_p"
2336 else:
2337 param = "obj"
2338
2339 out.write("""
2340/**
2341 * Initialize an object of type %(cls)s.
2342 *
2343 * @param obj Pointer to the object to initialize
2344 * @param version The wire version to use for the object
2345 * @param bytes How many bytes in the object
2346 * @param clean_wire Boolean: If true, clear the wire object control struct
2347 *
2348 * If bytes < 0, then the default fixed length is used for the object
2349 *
2350 * This is a "coerce" function that sets up the pointers for the
Andreas Wundsam53256162013-05-02 14:05:53 -07002351 * accessors properly.
Rich Lanea06d0c32013-03-25 08:52:03 -07002352 *
2353 * If anything other than 0 is passed in for the buffer size, the underlying
2354 * wire buffer will have 'grow' called.
2355 */
2356
2357void
2358%(cls)s_init(%(cls)s_t *%(param)s,
2359 of_version_t version, int bytes, int clean_wire)
2360{
2361""" % dict(cls=cls, param=param))
2362
2363 # Use an extra pointer to deal with inheritance classes
2364 if cls in type_maps.inheritance_map:
2365 out.write("""\
2366 %s_header_t *obj;
2367
2368 obj = &obj_p->header; /* Need instantiable subclass */
2369""" % cls)
2370
2371 out.write("""
2372 ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
2373 if (clean_wire) {
2374 MEMSET(obj, 0, sizeof(*obj));
2375 }
2376 if (bytes < 0) {
Rich Lanef70be942013-07-18 13:33:14 -07002377 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002378 }
2379 obj->version = version;
2380 obj->length = bytes;
2381 obj->object_id = %(enum)s;
2382""" % dict(cls=cls, enum=enum_name(cls)))
2383 gen_coerce_ops(out, cls)
2384
2385 out.write("""
2386 /* Grow the wire buffer */
2387 if (obj->wire_object.wbuf != NULL) {
2388 int tot_bytes;
2389
2390 tot_bytes = bytes + obj->wire_object.obj_offset;
2391 of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
2392 }
2393}
2394
2395""")
2396
2397## @fixme This should also be updated once there is a map from
2398# class instance to wire length/type accessors
2399def gen_wire_push_fn(cls, out):
2400 """
2401 Generate the calls to push values into the wire buffer
2402 """
2403 if type_maps.class_is_virtual(cls):
2404 print "Push fn gen called for virtual class " + cls
2405 return
2406
2407 out.write("""
2408/**
2409 * Helper function to push values into the wire buffer
2410 */
2411static inline int
2412%(cls)s_push_wire_values(%(cls)s_t *obj)
2413{
2414""" % dict(cls=cls))
2415
Rich Lanebdd8e292013-12-06 17:37:39 -08002416 import loxi_globals
2417 uclass = loxi_globals.unified.class_by_name(cls)
2418 if uclass and not uclass.virtual and uclass.has_type_members:
2419 out.write("""
2420 %(cls)s_push_wire_types(obj);
2421""" % dict(cls=cls))
2422
Rich Lanea06d0c32013-03-25 08:52:03 -07002423 if loxi_utils.class_is_message(cls):
2424 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002425 /* Message obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002426 of_message_t msg;
2427
2428 if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07002429 of_message_length_set(msg, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002430 }
2431""" % dict(name = enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07002432
Rich Lanea06d0c32013-03-25 08:52:03 -07002433 else: # Not a message
2434 if loxi_utils.class_is_tlv16(cls):
2435 out.write("""
Rich Lanebdd8e292013-12-06 17:37:39 -08002436 /* TLV obj; set length */
Rich Lanea06d0c32013-03-25 08:52:03 -07002437 of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
Rich Lanea06d0c32013-03-25 08:52:03 -07002438""" % dict(enum=enum_name(cls)))
Rich Lanea06d0c32013-03-25 08:52:03 -07002439
Rich Lanea06d0c32013-03-25 08:52:03 -07002440 if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
2441 out.write("""
2442 obj->wire_length_set((of_object_t *)obj, obj->length);
2443""")
2444
2445 if cls == "of_meter_stats":
2446 out.write("""
2447 of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
2448""" % dict(enum=enum_name(cls)))
2449
2450 out.write("""
2451 return OF_ERROR_NONE;
2452}
2453""")
2454
2455def gen_new_fn_body(cls, out):
2456 """
2457 Generate function body for new function
2458 @param cls The class name for the function
2459 @param out The file to which to write
2460 """
2461
2462 out.write("""
2463/**
2464 * \\defgroup %(cls)s %(cls)s
2465 */
2466""" % dict(cls=cls))
2467
2468 if not type_maps.class_is_virtual(cls):
2469 gen_wire_push_fn(cls, out)
2470
2471 out.write("""
2472/**
2473 * Create a new %(cls)s object
2474 *
2475 * @param version The wire version to use for the object
2476 * @return Pointer to the newly create object or NULL on error
2477 *
2478 * Initializes the new object with it's default fixed length associating
2479 * a new underlying wire buffer.
2480 *
2481 * Use new_from_message to bind an existing message to a message object,
2482 * or a _get function for non-message objects.
2483 *
2484 * \\ingroup %(cls)s
2485 */
2486
2487%(cls)s_t *
2488%(cls)s_new_(of_version_t version)
2489{
2490 %(cls)s_t *obj;
2491 int bytes;
2492
Rich Lanef70be942013-07-18 13:33:14 -07002493 bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
Rich Lanea06d0c32013-03-25 08:52:03 -07002494
2495 /* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
2496 if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
2497 return NULL;
2498 }
2499
2500 %(cls)s_init(obj, version, bytes, 0);
2501""" % dict(cls=cls, enum=enum_name(cls)))
2502 if not type_maps.class_is_virtual(cls):
2503 out.write("""
2504 if (%(cls)s_push_wire_values(obj) < 0) {
2505 FREE(obj);
2506 return NULL;
2507 }
2508""" % dict(cls=cls))
2509
2510 match_offset = v3_match_offset_get(cls)
2511 if match_offset >= 0:
2512 # Init length field for match object
2513 out.write("""
2514 /* Initialize match TLV for 1.2 */
2515 /* FIXME: Check 1.3 below */
2516 if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
2517 of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
2518 }
2519""" % dict(match_offset=match_offset))
2520 out.write("""
2521 return obj;
2522}
2523
2524#if defined(OF_OBJECT_TRACKING)
2525
2526/*
2527 * Tracking objects. Call the new function and then record location
2528 */
2529
2530%(cls)s_t *
2531%(cls)s_new_tracking(of_version_t version,
2532 const char *file, int line)
2533{
2534 %(cls)s_t *obj;
2535
2536 obj = %(cls)s_new_(version);
2537 of_object_track((of_object_t *)obj, file, line);
2538
2539 return obj;
2540}
2541#endif
2542""" % dict(cls=cls))
2543
2544
2545def gen_from_message_fn_body(cls, out):
2546 """
2547 Generate function body for from_message function
2548 @param cls The class name for the function
2549 @param out The file to which to write
2550 """
2551 out.write("""
2552/**
2553 * Create a new %(cls)s object and bind it to an existing message
2554 *
2555 * @param msg The message to bind the new object to
2556 * @return Pointer to the newly create object or NULL on error
2557 *
2558 * \ingroup %(cls)s
2559 */
2560
2561%(cls)s_t *
2562%(cls)s_new_from_message_(of_message_t msg)
2563{
2564 %(cls)s_t *obj = NULL;
2565 of_version_t version;
2566 int length;
2567
2568 if (msg == NULL) return NULL;
2569
2570 version = of_message_version_get(msg);
2571 if (!OF_VERSION_OKAY(version)) return NULL;
2572
2573 length = of_message_length_get(msg);
2574
2575 if ((obj = (%(cls)s_t *)of_object_new(-1)) == NULL) {
2576 return NULL;
2577 }
2578
2579 %(cls)s_init(obj, version, 0, 0);
2580
2581 if ((of_object_buffer_bind((of_object_t *)obj, OF_MESSAGE_TO_BUFFER(msg),
2582 length, OF_MESSAGE_FREE_FUNCTION)) < 0) {
2583 FREE(obj);
2584 return NULL;
2585 }
2586 obj->length = length;
2587 obj->version = version;
2588
2589 return obj;
2590}
2591
2592#if defined(OF_OBJECT_TRACKING)
2593
2594/*
2595 * Tracking objects. Call the new function and then record location
2596 */
2597
2598%(cls)s_t *
2599%(cls)s_new_from_message_tracking(of_message_t msg,
2600 const char *file, int line)
2601{
2602 %(cls)s_t *obj;
2603
2604 obj = %(cls)s_new_from_message_(msg);
2605 of_object_track((of_object_t *)obj, file, line);
2606
2607 return obj;
2608}
2609#endif
2610""" % dict(cls=cls))
2611
2612
2613################################################################
2614# Now the top level generator functions
2615################################################################
2616
2617def gen_new_function_declarations(out):
2618 """
2619 Gerenate the header file declarations for new operators for all classes
2620 @param out The file to which to write the decs
2621 """
2622
2623 out.write("""
2624/****************************************************************
2625 *
2626 * New operator declarations
2627 *
2628 * _new: Create a new object for writing; includes init
2629 * _new_from_message: Create a new instance of the object and bind the
2630 * message data to the object
2631 * _init: Initialize and optionally allocate buffer space for an
2632 * automatic instance
2633 *
2634 * _new and _from_message require a delete operation to be called
2635 * on the object.
2636 *
2637 ****************************************************************/
2638""")
2639 out.write("""
2640/*
2641 * If object tracking is enabled, map "new" and "new from msg"
2642 * calls to tracking versions; otherwise, directly to internal
2643 * versions of fns which have the same name but end in _.
2644 */
2645
2646#if defined(OF_OBJECT_TRACKING)
2647""")
2648 for cls in of_g.standard_class_order:
2649 out.write("""
2650extern %(cls)s_t *
2651 %(cls)s_new_tracking(of_version_t version,
2652 const char *file, int line);
2653#define %(cls)s_new(version) \\
2654 %(cls)s_new_tracking(version, \\
2655 __FILE__, __LINE__)
2656""" % dict(cls=cls))
2657 if loxi_utils.class_is_message(cls):
2658 out.write("""extern %(cls)s_t *
2659 %(cls)s_new_from_message_tracking(of_message_t msg,
2660 const char *file, int line);
2661#define %(cls)s_new_from_message(msg) \\
2662 %(cls)s_new_from_message_tracking(msg, \\
2663 __FILE__, __LINE__)
2664""" % dict(cls=cls))
2665
2666 out.write("""
2667#else /* No object tracking */
2668""")
2669 for cls in of_g.standard_class_order:
2670 out.write("""
2671#define %(cls)s_new(version) \\
2672 %(cls)s_new_(version)
2673""" % dict(cls=cls))
2674 if loxi_utils.class_is_message(cls):
2675 out.write("""#define %(cls)s_new_from_message(msg) \\
2676 %(cls)s_new_from_message_(msg)
2677""" % dict(cls=cls))
2678
2679 out.write("""
2680#endif /* Object tracking */
2681""")
2682
2683 for cls in of_g.standard_class_order:
2684 out.write("""
2685extern %(cls)s_t *
2686 %(cls)s_new_(of_version_t version);
2687""" % dict(cls=cls))
2688 if loxi_utils.class_is_message(cls):
2689 out.write("""extern %(cls)s_t *
2690 %(cls)s_new_from_message_(of_message_t msg);
2691""" % dict(cls=cls))
2692 out.write("""extern void %(cls)s_init(
2693 %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
2694""" % dict(cls=cls))
2695
2696 out.write("""
2697/****************************************************************
2698 *
2699 * Delete operator static inline definitions.
2700 * These are here for type checking purposes only
2701 *
2702 ****************************************************************/
2703""")
2704 for cls in of_g.standard_class_order:
2705# if cls in type_maps.inheritance_map:
2706# continue
2707 out.write("""
2708/**
2709 * Delete an object of type %(cls)s_t
2710 * @param obj An instance of type %(cls)s_t
2711 *
2712 * \ingroup %(cls)s
2713 */
2714static inline void
2715%(cls)s_delete(%(cls)s_t *obj) {
2716 of_object_delete((of_object_t *)(obj));
2717}
2718""" % dict(cls=cls))
2719
2720 out.write("""
2721typedef void (*of_object_init_f)(of_object_t *obj, of_version_t version,
2722 int bytes, int clean_wire);
Rich Laneb157b0f2013-03-27 13:55:28 -07002723extern const of_object_init_f of_object_init_map[];
Rich Lanea06d0c32013-03-25 08:52:03 -07002724""")
2725
2726 out.write("""
2727/****************************************************************
2728 *
2729 * Function pointer initialization functions
2730 * These are part of the "coerce" type casting for objects
2731 *
2732 ****************************************************************/
2733""")
2734
2735#
2736# @fixme Not clear that these should all be set for virtual fns
2737#
2738# @fixme Clean up. should have a (language specific) map from class
2739# to length and type get/set functions
2740#
2741
2742def gen_coerce_ops(out, cls):
2743 out.write("""
2744 /* Set up the object's function pointers */
2745""")
2746
Rich Lane92feca82013-12-10 15:57:13 -08002747 uclass = loxi_globals.unified.class_by_name(cls)
2748 if uclass and not uclass.virtual and uclass.has_type_members:
2749 out.write("""
2750 obj->wire_type_set = %(cls)s_push_wire_types;
2751""" % dict(cls=cls))
2752
Rich Lanea06d0c32013-03-25 08:52:03 -07002753 if loxi_utils.class_is_message(cls):
2754 out.write("""
2755 obj->wire_length_get = of_object_message_wire_length_get;
2756 obj->wire_length_set = of_object_message_wire_length_set;
2757""")
2758 else:
2759 if loxi_utils.class_is_tlv16(cls):
2760 if not (cls in type_maps.inheritance_map): # Don't set for super
2761 out.write("""
2762 obj->wire_length_set = of_tlv16_wire_length_set;
Rich Lanea06d0c32013-03-25 08:52:03 -07002763""")
2764 out.write("""
2765 obj->wire_length_get = of_tlv16_wire_length_get;
2766""")
2767 if loxi_utils.class_is_action(cls):
2768 out.write("""
2769 obj->wire_type_get = of_action_wire_object_id_get;
2770""")
2771 if loxi_utils.class_is_action_id(cls):
2772 out.write("""
2773 obj->wire_type_get = of_action_id_wire_object_id_get;
2774""")
2775 if loxi_utils.class_is_instruction(cls):
2776 out.write("""
2777 obj->wire_type_get = of_instruction_wire_object_id_get;
2778""")
2779 if loxi_utils.class_is_queue_prop(cls):
2780 out.write("""
2781 obj->wire_type_get = of_queue_prop_wire_object_id_get;
2782""")
2783 if loxi_utils.class_is_table_feature_prop(cls):
2784 out.write("""
2785 obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
2786""")
2787 if loxi_utils.class_is_meter_band(cls):
2788 out.write("""
2789 obj->wire_type_get = of_meter_band_wire_object_id_get;
2790""")
2791 if loxi_utils.class_is_hello_elem(cls):
2792 out.write("""
2793 obj->wire_type_get = of_hello_elem_wire_object_id_get;
2794""")
2795 if loxi_utils.class_is_oxm(cls):
2796 out.write("""
2797 obj->wire_length_get = of_oxm_wire_length_get;
Rich Lanea06d0c32013-03-25 08:52:03 -07002798 obj->wire_type_get = of_oxm_wire_object_id_get;
Rich Lanea06d0c32013-03-25 08:52:03 -07002799""")
2800 if loxi_utils.class_is_u16_len(cls):
2801 out.write("""
2802 obj->wire_length_get = of_u16_len_wire_length_get;
2803 obj->wire_length_set = of_u16_len_wire_length_set;
2804""")
2805 if cls == "of_packet_queue":
2806 out.write("""
2807 obj->wire_length_get = of_packet_queue_wire_length_get;
2808 obj->wire_length_set = of_packet_queue_wire_length_set;
2809""")
2810# if cls == "of_list_meter_band_stats":
2811# out.write("""
2812# obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
2813#""")
2814 if cls == "of_meter_stats":
2815 out.write("""
2816 obj->wire_length_get = of_meter_stats_wire_length_get;
2817 obj->wire_length_set = of_meter_stats_wire_length_set;
2818""")
2819
2820 if config_check("gen_fn_ptrs"):
2821 if loxi_utils.class_is_list(cls):
2822 out.write("""
2823 obj->first = %(cls)s_first;
2824 obj->next = %(cls)s_next;
2825 obj->append = %(cls)s_append;
2826 obj->append_bind = %(cls)s_append_bind;
2827""" % dict(cls=cls))
2828 else:
2829 instantiate_fn_ptrs(cls, 4, out)
2830
Rich Laneb604e332013-12-15 13:23:51 -08002831def gen_new_function_definitions(out, cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07002832 """
2833 Generate the new operator for all classes
2834
2835 @param out The file to which to write the functions
2836 """
2837
Rich Laneb604e332013-12-15 13:23:51 -08002838 gen_new_fn_body(cls, out)
2839 gen_init_fn_body(cls, out)
2840 if loxi_utils.class_is_message(cls):
2841 gen_from_message_fn_body(cls, out)
Rich Lanea06d0c32013-03-25 08:52:03 -07002842
2843def gen_init_map(out):
2844 """
2845 Generate map from object ID to type coerce function
2846 """
2847 out.write("""
2848/**
2849 * Map from object ID to type coerce function
2850 */
Rich Laneb157b0f2013-03-27 13:55:28 -07002851const of_object_init_f of_object_init_map[] = {
Rich Lanea06d0c32013-03-25 08:52:03 -07002852 (of_object_init_f)NULL,
2853""")
2854 count = 1
2855 for i, cls in enumerate(of_g.standard_class_order):
2856 if count != of_g.unified[cls]["object_id"]:
2857 print "Error in class mapping: object IDs not sequential"
2858 print cls, count, of_g.unified[cls]["object_id"]
2859 sys.exit(1)
2860 s = "(of_object_init_f)%s_init" % cls
2861 if cls in type_maps.inheritance_map:
2862 s = "(of_object_init_f)%s_header_init" % cls
2863 if i < len(of_g.standard_class_order) - 1:
2864 s += ","
2865 out.write(" %-65s /* %d */\n" % (s, count))
2866 count += 1
2867 out.write("};\n")
2868
2869"""
2870Document generation functions
2871
2872The main reason this is here is to generate documentation per
2873accessor that indicates the versions that support the interface.
2874"""
2875
2876
2877def gen_accessor_doc(out, name):
2878 """
2879 Generate documentation for each accessor function that indicates
2880 the versions supporting the accessor.
2881 """
2882
2883 common_top_matter(out, name)
2884
2885 out.write("/* DOCUMENTATION ONLY */\n")
2886
2887 for cls in of_g.standard_class_order:
2888 if cls in type_maps.inheritance_map:
2889 pass # Check this
2890
2891 out.write("""
2892/**
Andreas Wundsam53256162013-05-02 14:05:53 -07002893 * Structure for %(cls)s object. Get/set
Rich Lanea06d0c32013-03-25 08:52:03 -07002894 * accessors available in all versions unless noted otherwise
2895 *
2896""" % dict(cls=cls))
2897 if loxi_utils.class_is_list(cls):
2898 out.write("""\
2899 * @param first Function of type %(cls)s_first_f.
2900 * Setup a TBD class object to the first entry in the list
2901 * @param next Function of type %(cls)s_next_f.
2902 * Advance a TBD class object to the next entry in the list
2903 * @param append_bind Function of type %(cls)s_append_bind_f
2904 * Setup a TBD class object for append to the end of the current list
2905 * @param append Function of type @ref %(cls)s_append_f.
2906 * Copy an item to the end of a list
2907""" % dict(cls=cls))
2908
2909 for m_name in of_g.ordered_members[cls]:
2910 if m_name in of_g.skip_members:
2911 continue
2912 ver_type_map = field_ver_get(cls, m_name)
2913 (m_type, get_rv) = get_acc_rv(cls, m_name)
2914 if len(ver_type_map) == 3:
2915 # ver_string = "Available in all versions"
2916 ver_string = ""
2917 else:
2918 ver_string = "("
2919 for ver in sorted(ver_type_map):
2920 ver_string += " " + of_g.short_version_names[ver]
2921 ver_string += ")."
2922
2923 f_name = acc_name(cls, m_name)
2924 out.write("""\
2925 * @param %(m_name)s_get/set %(ver_string)s
2926 * Accessors for %(m_name)s, a variable of type %(m_type)s. Functions
2927 * are of type %(f_name)s_get_f and _set_f.
2928 *
2929""" % dict(f_name=f_name, m_name=m_name, ver_string=ver_string, m_type=m_type))
2930
2931 out.write("""\
2932 */
2933typedef struct %(cls)s_s %(cls)s_t;
2934""" % dict(cls=cls))
2935
2936 out.write("#endif /* _LOCI_DOC_H_ */\n")
2937
2938################################################################
2939#
2940# For fun, here are some unified, traditional C structure representation
2941#
2942################################################################
2943
2944def gen_cof_to_wire(out):
2945 pass
2946
2947def gen_wire_to_cof(out):
2948 pass
2949
2950def gen_cof_instance(out, cls):
2951 out.write("struct c%s_s {\n" % cls)
2952 for m in of_g.ordered_members[cls]:
2953 if m in of_g.skip_members:
2954 continue
2955 entry = of_g.unified[cls]["union"][m]
2956 cof_type = type_to_cof_type(entry["m_type"])
2957 out.write(" %-20s %s;\n" % (cof_type, m))
2958 out.write("};\n\n");
2959
2960def gen_cof_structs(out):
2961 """
2962 Generate non-version specific (common) representation of structures
2963
2964 @param out The file to which to write the functions
2965 """
2966
2967 out.write("\n/* Common, unified OpenFlow structure representations */\n")
2968 for cls in of_g.standard_class_order:
2969 if cls in type_maps.inheritance_map:
2970 continue
2971 gen_cof_instance(out, cls)
2972
2973################################################################
2974#
2975# Generate code samples for applications.
2976#
2977################################################################
2978
2979def gen_code_samples(out, name):
2980 out.write("""
2981#if 0 /* Do not compile in */
2982/**
2983 * @file %(name)s
2984 *
2985 * These are code samples for inclusion in other components
2986 */
2987
2988""" % dict(name=name))
2989
2990 gen_jump_table_template(out)
2991 # These are messages that a switch might expect.
2992 msg_list = ["of_echo_request",
2993 "of_hello",
2994 "of_packet_in",
2995 "of_packet_out",
2996 "of_port_mod",
2997 "of_port_stats_request",
2998 "of_queue_get_config_request",
2999 "of_queue_stats_request",
3000 "of_flow_add",
3001 "of_flow_modify",
3002 "of_flow_modify_strict",
3003 "of_flow_delete",
3004 "of_flow_delete_strict",
3005 "of_get_config_request",
3006 "of_flow_stats_request",
3007 "of_barrier_request",
3008 "of_echo_reply",
3009 "of_aggregate_stats_request",
3010 "of_desc_stats_request",
3011 "of_table_stats_request",
3012 "of_features_request",
3013 "of_table_mod",
3014 "of_set_config",
3015 "of_experimenter",
3016 "of_experimenter_stats_request",
3017 "of_group_desc_stats_request",
3018 "of_group_features_stats_request",
3019 "of_role_request"]
3020
3021 gen_message_handler_templates(out, msgs=msg_list)
3022
3023 out.write("""
3024#endif
3025""")
3026
3027def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07003028 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07003029 unhandled="unhandled_message"):
3030 """
3031 Generate a template for a jump table.
3032 @param out The file to which to write the functions
3033 """
3034 out.write("""
3035/*
3036 * Simple jump table definition for message handling
3037 */
3038typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
3039typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
3040
3041/* Jump table template for message objects */
3042extern msg_jump_table_t jump_table;
3043
3044/* C-code template */
3045msg_jump_table_t jump_table = {
3046 %(unhandled)s, /* OF_OBJECT; place holder for generic object */
3047""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3048 count = 0
3049 fn_name = unhandled
3050 for cls in of_g.ordered_messages:
3051 comma = ","
3052 count += 1
3053 if count == len(of_g.ordered_messages):
3054 comma = " "
3055 if not all_unhandled:
3056 fn_name = "%s_handler" % cls[3:]
3057 out.write(" %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
Andreas Wundsam53256162013-05-02 14:05:53 -07003058
Rich Lanea06d0c32013-03-25 08:52:03 -07003059 out.write("};\n")
3060
3061def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
Andreas Wundsam53256162013-05-02 14:05:53 -07003062 cxn_type="ls_cxn_handle_t",
Rich Lanea06d0c32013-03-25 08:52:03 -07003063 unhandled="unhandled_message"):
3064 out.write("""
3065/*
3066 * Simple switch statement for message handling
3067 */
3068
3069 switch (obj->object_id):
3070""")
3071 fn_name = unhandled
3072 for cls in of_g.ordered_messages:
3073 if not all_unhandled:
3074 fn_name = "%s_handler" % cls[3:]
3075 out.write("""
3076 case %(enum)s:
3077 rv = %(fn_name)s(cxn, obj);
3078 break;
3079""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
3080 out.write("""
3081 default:
3082 rv = LS_ERROR_PARAM;
3083 break;
3084 }
3085
3086 TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
3087
3088 return rv;
3089""")
3090
3091
3092def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
3093 unhandled="unhandled_message", msgs=None):
3094 gen_jump_table_template(out, False, cxn_type)
3095 out.write("""
3096/**
3097 * Function for unhandled message
3098 */
3099static int
3100unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
3101{
3102 (void)cxn;
3103 (void)obj;
3104 TRACE("Unhandled message %%p. Object id %%d", obj, obj->object_id);
3105
3106 return LS_ERROR_UNAVAIL;
3107}
3108""" % dict(unhandled=unhandled, cxn_type=cxn_type))
3109
3110 if not msgs:
3111 msgs = of_g.ordered_messages
3112 for cls in msgs:
3113 out.write("""
3114/**
3115 * Handle a %(s_cls)s message
3116 * @param cxn Connection handler for the owning connection
3117 * @param _obj Generic type object for the message to be coerced
3118 * @returns Error code
3119 */
3120
3121static int
3122%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
3123{
3124 %(cls)s_t *obj;
3125
3126 TRACE("Handling %(cls)s message: %%p.", obj);
3127 obj = (%(cls)s_t *)_obj;
3128
3129 /* Handle object of type %(cls)s_t */
3130
3131 return LS_ERROR_NONE;
3132}
3133""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
3134 gen_message_switch_stmt_tmeplate(out, False, cxn_type)
3135
3136def gen_setup_from_add_fns(out):
3137 """
3138 Generate functions that setup up objects based on an add
3139
3140 Okay, this is getting out of hand. We need to refactor the code
3141 so that this can be done without so much pain.
3142 """
3143 out.write("""
3144
3145/* Flow stats entry setup for all versions */
3146
3147static int
3148flow_stats_entry_setup_from_flow_add_common(of_flow_stats_entry_t *obj,
3149 of_flow_add_t *flow_add,
3150 of_object_t *effects,
3151 int entry_match_offset,
3152 int add_match_offset)
3153{
Rich Lanea06d0c32013-03-25 08:52:03 -07003154 int entry_len, add_len;
3155 of_wire_buffer_t *wbuf;
3156 int abs_offset;
3157 int delta;
3158 uint16_t val16;
3159 uint64_t cookie;
3160 of_octets_t match_octets;
3161
Rich Lanea06d0c32013-03-25 08:52:03 -07003162 /* Transfer the match underlying object from add to stats entry */
3163 wbuf = OF_OBJECT_TO_WBUF(obj);
3164 entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset);
3165 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3166
3167 match_octets.bytes = add_len;
3168 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3169
3170 /* Copy data into flow entry */
3171 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, entry_match_offset);
3172 of_wire_buffer_replace_data(wbuf, abs_offset, entry_len,
3173 match_octets.data, add_len);
3174
3175 /* Not scalar, update lengths if needed */
3176 delta = add_len - entry_len;
3177 if (delta != 0) {
3178 /* Update parent(s) */
3179 of_object_parent_length_update((of_object_t *)obj, delta);
3180 }
3181
3182 of_flow_add_cookie_get(flow_add, &cookie);
3183 of_flow_stats_entry_cookie_set(obj, cookie);
3184
3185 of_flow_add_priority_get(flow_add, &val16);
3186 of_flow_stats_entry_priority_set(obj, val16);
3187
3188 of_flow_add_idle_timeout_get(flow_add, &val16);
3189 of_flow_stats_entry_idle_timeout_set(obj, val16);
3190
3191 of_flow_add_hard_timeout_get(flow_add, &val16);
3192 of_flow_stats_entry_hard_timeout_set(obj, val16);
3193
Rich Lane9277a962013-07-12 09:37:41 -07003194 /* Effects may come from different places */
3195 if (effects != NULL) {
3196 if (obj->version == OF_VERSION_1_0) {
3197 OF_TRY(of_flow_stats_entry_actions_set(obj,
3198 (of_list_action_t *)effects));
3199 } else {
3200 OF_TRY(of_flow_stats_entry_instructions_set(obj,
3201 (of_list_instruction_t *)effects));
3202 }
3203 } else {
3204 if (obj->version == OF_VERSION_1_0) {
3205 of_list_action_t actions;
3206 of_flow_add_actions_bind(flow_add, &actions);
3207 OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
3208 } else {
3209 of_list_instruction_t instructions;
3210 of_flow_add_instructions_bind(flow_add, &instructions);
3211 OF_TRY(of_flow_stats_entry_instructions_set(obj, &instructions));
3212 }
3213 }
3214
Rich Lanea06d0c32013-03-25 08:52:03 -07003215 return OF_ERROR_NONE;
3216}
3217
3218/* Flow removed setup for all versions */
3219
3220static int
3221flow_removed_setup_from_flow_add_common(of_flow_removed_t *obj,
3222 of_flow_add_t *flow_add,
3223 int removed_match_offset,
3224 int add_match_offset)
3225{
3226 int add_len, removed_len;
3227 of_wire_buffer_t *wbuf;
3228 int abs_offset;
3229 int delta;
3230 uint16_t val16;
3231 uint64_t cookie;
3232 of_octets_t match_octets;
3233
3234 /* Transfer the match underlying object from add to removed obj */
3235 wbuf = OF_OBJECT_TO_WBUF(obj);
3236 removed_len = _WIRE_MATCH_PADDED_LEN(obj, removed_match_offset);
3237 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3238
3239 match_octets.bytes = add_len;
3240 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3241
3242 /* Copy data into flow removed */
3243 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, removed_match_offset);
3244 of_wire_buffer_replace_data(wbuf, abs_offset, removed_len,
3245 match_octets.data, add_len);
3246
3247 /* Not scalar, update lengths if needed */
3248 delta = add_len - removed_len;
3249 if (delta != 0) {
3250 /* Update parent(s) */
3251 of_object_parent_length_update((of_object_t *)obj, delta);
3252 }
3253
3254 of_flow_add_cookie_get(flow_add, &cookie);
3255 of_flow_removed_cookie_set(obj, cookie);
3256
3257 of_flow_add_priority_get(flow_add, &val16);
3258 of_flow_removed_priority_set(obj, val16);
3259
3260 of_flow_add_idle_timeout_get(flow_add, &val16);
3261 of_flow_removed_idle_timeout_set(obj, val16);
Andreas Wundsam53256162013-05-02 14:05:53 -07003262
Rich Lanea06d0c32013-03-25 08:52:03 -07003263 if (obj->version >= OF_VERSION_1_2) {
3264 of_flow_add_hard_timeout_get(flow_add, &val16);
3265 of_flow_removed_hard_timeout_set(obj, val16);
3266 }
3267
3268 return OF_ERROR_NONE;
3269}
3270
3271/* Set up a flow removed message from the original add */
3272
3273int
3274of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
3275 of_flow_add_t *flow_add)
3276{
3277 switch (obj->version) {
3278 case OF_VERSION_1_0:
Andreas Wundsam53256162013-05-02 14:05:53 -07003279 return flow_removed_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003280 8, 8);
3281 break;
3282 case OF_VERSION_1_1:
3283 case OF_VERSION_1_2:
3284 case OF_VERSION_1_3:
Andreas Wundsam53256162013-05-02 14:05:53 -07003285 return flow_removed_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003286 48, 48);
3287 break;
3288 default:
3289 return OF_ERROR_VERSION;
3290 break;
3291 }
3292
3293 return OF_ERROR_NONE;
3294}
3295
3296
3297/* Set up a packet in message from the original add */
3298
3299int
3300of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
3301 of_flow_add_t *flow_add)
3302{
3303 int add_len, pkt_in_len;
3304 of_wire_buffer_t *wbuf;
3305 int abs_offset;
3306 int delta;
3307 const int pkt_in_match_offset = 16;
3308 const int add_match_offset = 48;
3309 of_octets_t match_octets;
3310
3311 if (obj->version < OF_VERSION_1_2) {
3312 /* Nothing to be done before OF 1.2 */
3313 return OF_ERROR_NONE;
3314 }
3315
3316 /* Transfer match struct from flow add to packet in object */
3317 wbuf = OF_OBJECT_TO_WBUF(obj);
3318 pkt_in_len = _WIRE_MATCH_PADDED_LEN(obj, pkt_in_match_offset);
3319 add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
3320
3321 match_octets.bytes = add_len;
3322 match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
3323
3324 /* Copy data into pkt_in msg */
3325 abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, pkt_in_match_offset);
3326 of_wire_buffer_replace_data(wbuf, abs_offset, pkt_in_len,
3327 match_octets.data, add_len);
3328
3329 /* Not scalar, update lengths if needed */
3330 delta = add_len - pkt_in_len;
3331 if (delta != 0) {
3332 /* Update parent(s) */
3333 of_object_parent_length_update((of_object_t *)obj, delta);
3334 }
3335
3336 return OF_ERROR_NONE;
3337}
3338
3339/* Set up a stats entry from the original add */
3340
3341int
3342of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
3343 of_flow_add_t *flow_add,
3344 of_object_t *effects)
3345{
3346 switch (obj->version) {
3347 case OF_VERSION_1_0:
3348 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
3349 effects, 4, 8);
3350 break;
3351 case OF_VERSION_1_1:
3352 case OF_VERSION_1_2:
3353 case OF_VERSION_1_3:
Andreas Wundsam53256162013-05-02 14:05:53 -07003354 return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
Rich Lanea06d0c32013-03-25 08:52:03 -07003355 effects, 48, 48);
3356 break;
3357 default:
3358 return OF_ERROR_VERSION;
3359 }
3360
3361 return OF_ERROR_NONE;
3362}
3363""")