loci: generate wire type parsers from the IR
Every virtual class gets a function that reads the discriminator and returns an
object id. If the subclass is a virtual class then the parsing recurses.
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 121bc42..6f0f6e9 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -78,6 +78,34 @@
class_name=uclass.name,
versioned_type_members=versioned_type_members)
+ParseWireTypesData = namedtuple('ParseWireTypesData',
+ ['class_name', 'versioned'])
+ParseWireTypesVersion = namedtuple('ParseWireTypesVersion',
+ ['discriminator', 'subclasses'])
+ParseWireTypesSubclass = namedtuple('ParseWireTypesSubclass',
+ ['class_name', 'value', 'virtual'])
+
+def parse_wire_types_data(uclass):
+ if not uclass.virtual:
+ return None
+
+ discriminator = uclass.discriminator
+
+ # Generate a dict of version -> ParseWireTypesVersion
+ versioned = {}
+ for version, ofclass in sorted(uclass.version_classes.items()):
+ subclasses = [ParseWireTypesSubclass(class_name=subclass.name,
+ value=subclass.member_by_name(discriminator.name).value,
+ virtual=subclass.virtual)
+ for subclass in ofclass.protocol.classes if subclass.superclass and subclass.superclass.name == ofclass.name]
+
+ subclasses.sort(key=lambda x: x.value)
+ versioned[version] = ParseWireTypesVersion(discriminator=discriminator,
+ subclasses=subclasses)
+
+ return ParseWireTypesData(class_name=uclass.name,
+ versioned=sorted(versioned.items()))
+
# Output multiple LOCI classes into each C file. This reduces the overhead of
# parsing header files, which takes longer than compiling the actual code
# for many classes. It also reduces the compiled code size.
@@ -86,7 +114,8 @@
with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
for uclass in chunk:
util.render_template(out, "class.c",
- push_wire_types_data=push_wire_types_data(uclass))
+ push_wire_types_data=push_wire_types_data(uclass),
+ parse_wire_types_data=parse_wire_types_data(uclass))
# Append legacy generated code
c_code_gen.gen_new_function_definitions(out, uclass.name)
c_code_gen.gen_accessor_definitions(out, uclass.name)
@@ -98,7 +127,8 @@
continue
with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
util.render_template(out, "class.c",
- push_wire_types_data=None)
+ push_wire_types_data=None,
+ parse_wire_types_data=None)
# Append legacy generated code
c_code_gen.gen_new_function_definitions(out, cls)
c_code_gen.gen_accessor_definitions(out, cls)
@@ -119,7 +149,8 @@
for cls in of_g.ordered_list_objects:
with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
util.render_template(out, "class.c",
- push_wire_types_data=None)
+ push_wire_types_data=None,
+ parse_wire_types_data=None)
# Append legacy generated code
c_code_gen.gen_new_function_definitions(out, cls)
c_code_gen.gen_list_accessors(out, cls)
diff --git a/c_gen/templates/_parse_wire_types.c b/c_gen/templates/_parse_wire_types.c
new file mode 100644
index 0000000..81878e6
--- /dev/null
+++ b/c_gen/templates/_parse_wire_types.c
@@ -0,0 +1,68 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+void
+${data.class_name}_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+ unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
+ switch (obj->version) {
+:: for version, version_data in data.versioned:
+ case ${version.constant_version(prefix='OF_VERSION_')}: {
+:: m = version_data.discriminator
+:: if m.length == 1:
+ uint8_t value = *(uint8_t *)(buf + ${m.offset}); /* ${m.name} */
+:: elif m.length == 2:
+ uint16_t value = U16_NTOH(*(uint16_t *)(buf + ${m.offset})); /* ${m.name} */
+:: elif m.length == 4:
+ uint32_t value = U32_NTOH(*(uint32_t *)(buf + ${m.offset})); /* ${m.name} */
+:: elif m.length == 8:
+ uint64_t value = U64_NTOH(*(uint64_t *)(buf + ${m.offset})); /* ${m.name} */
+:: else:
+:: raise("unsupported parse_wire_types length %d" % m.length)
+:: #endif
+::
+ switch (value) {
+:: for subclass in version_data.subclasses:
+ case ${hex(subclass.value)}:
+:: if subclass.virtual:
+ ${subclass.class_name}_wire_object_id_get(obj, id);
+:: else:
+ *id = ${subclass.class_name.upper()};
+:: #endif
+ break;
+:: #endfor
+ default:
+ *id = ${data.class_name.upper()};
+ break;
+ }
+ break;
+ }
+:: #endfor
+ default:
+ LOCI_ASSERT(0);
+ }
+}
diff --git a/c_gen/templates/class.c b/c_gen/templates/class.c
index 044e03e..815dafa 100644
--- a/c_gen/templates/class.c
+++ b/c_gen/templates/class.c
@@ -35,3 +35,8 @@
:: include("_push_wire_types.c", data=push_wire_types_data)
:: #endif
+
+:: if parse_wire_types_data:
+:: include("_parse_wire_types.c", data=parse_wire_types_data)
+
+:: #endif
diff --git a/c_gen/templates/loci_classes.h b/c_gen/templates/loci_classes.h
index 3486055..12c07d1 100644
--- a/c_gen/templates/loci_classes.h
+++ b/c_gen/templates/loci_classes.h
@@ -25,11 +25,16 @@
:: # EPL for the specific language governing permissions and limitations
:: # under the EPL.
::
+:: import loxi_globals
:: include('_copyright.c')
::
#ifndef __LOCI_CLASSES_H__
#define __LOCI_CLASSES_H__
+:: for uclass in loxi_globals.unified.classes:
+void ${uclass.name}_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
+:: #endfor
+
${legacy_code}
#endif