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