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