loci: use IR to push wire types
The old code is disabled but not yet deleted.
The generated code looks like:
```
void
of_bsn_lacp_stats_reply_push_wire_types(of_object_t *obj)
{
unsigned char *buf = loci_object_to_buffer(obj);
switch (obj->version) {
case OF_VERSION_1_3:
*(uint8_t *)(buf + 0) = obj->version; /* version */
*(uint8_t *)(buf + 1) = 19; /* type */
*(uint16_t *)(buf + 8) = htobe16(65535); /* stats_type */
*(uint32_t *)(buf + 16) = htobe32(6035143); /* experimenter */
*(uint32_t *)(buf + 20) = htobe32(1); /* subtype */
break;
default:
UNREACHABLE();
}
}
```
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index e2bb467..cc40f77 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -785,6 +785,7 @@
#include <loci/loci.h>
#include <loci/of_object.h>
#include "loci_log.h"
+#include "loci_push_wire_types.h"
""")
gen_object_enum_str(out)
@@ -2687,62 +2688,36 @@
{
""" % dict(cls=cls))
+ import loxi_globals
+ uclass = loxi_globals.unified.class_by_name(cls)
+ if uclass and not uclass.virtual and uclass.has_type_members:
+ out.write("""
+ %(cls)s_push_wire_types(obj);
+""" % dict(cls=cls))
+
if loxi_utils.class_is_message(cls):
out.write("""
- /* Message obj; push version, length and type to wire */
+ /* Message obj; set length */
of_message_t msg;
if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
- of_message_version_set(msg, obj->version);
of_message_length_set(msg, obj->length);
- OF_TRY(of_wire_message_object_id_set(OF_OBJECT_TO_WBUF(obj),
- %(name)s));
}
""" % dict(name = enum_name(cls)))
- for version in of_g.of_version_range:
- if type_maps.class_is_extension(cls, version):
- exp_name = type_maps.extension_to_experimenter_macro_name(cls)
- subtype = type_maps.extension_message_to_subtype(cls, version)
- if subtype is None or exp_name is None:
- print "Error in mapping extension message"
- print cls, version
- sys.exit(1)
- out.write("""
- if (obj->version == %(version)s) {
- of_message_experimenter_id_set(OF_OBJECT_TO_MESSAGE(obj),
- %(exp_name)s);
- of_message_experimenter_subtype_set(OF_OBJECT_TO_MESSAGE(obj),
- %(subtype)s);
- }
-""" % dict(exp_name=exp_name, version=of_g.wire_ver_map[version],
- subtype=str(subtype)))
-
else: # Not a message
if loxi_utils.class_is_tlv16(cls):
out.write("""
- /* TLV obj; set length and type */
+ /* TLV obj; set length */
of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
- of_tlv16_wire_object_id_set((of_object_t *)obj,
- %(enum)s);
""" % dict(enum=enum_name(cls)))
- # Some tlv16 types may be extensions requiring more work
- if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
- "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
- "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl",
- "of_instruction_bsn_disable_src_mac_check"]:
- out.write("""
- /* Extended TLV obj; Call specific accessor */
- of_extension_object_id_set(obj, %(enum)s);
-""" % dict(cls=cls, enum=enum_name(cls)))
-
if loxi_utils.class_is_oxm(cls):
out.write("""\
- /* OXM obj; set length and type */
+ /* OXM obj; set length */
of_oxm_wire_length_set((of_object_t *)obj, obj->length);
- of_oxm_wire_object_id_set((of_object_t *)obj, %(enum)s);
""" % dict(enum=enum_name(cls)))
+
if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
out.write("""
obj->wire_length_set((of_object_t *)obj, obj->length);
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
new file mode 100644
index 0000000..0d7832a
--- /dev/null
+++ b/c_gen/codegen.py
@@ -0,0 +1,79 @@
+# 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.
+
+"""
+Code generation
+
+These functions extract data from the IR and render templates with it.
+"""
+
+from collections import namedtuple
+from itertools import groupby
+import template_utils
+import loxi_globals
+import loxi_ir.ir as ir
+import util
+
+PushWireTypesFn = namedtuple('PushWireTypesFn',
+ ['class_name', 'versioned_type_members'])
+PushWireTypesMember = namedtuple('PushWireTypesMember',
+ ['name', 'offset', 'length', 'value'])
+
+def gen_push_wire_types(install_dir):
+ fns = []
+ for uclass in loxi_globals.unified.classes:
+ if uclass.virtual or not uclass.has_type_members:
+ continue
+
+ # Generate a dict of version -> list of PushWireTypesMember
+ type_members_by_version = {}
+ for version, ofclass in sorted(uclass.version_classes.items()):
+ pwtms = []
+ for m in ofclass.members:
+ if isinstance(m, ir.OFTypeMember):
+ if m.name == "version" and m.value == version.wire_version:
+ # Special case for version
+ pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
+ else:
+ pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, m.value))
+ type_members_by_version[version] = pwtms
+
+ # Merge versions with identical type members
+ all_versions = sorted(type_members_by_version.keys())
+ versioned_type_members = []
+ for pwtms, versions in groupby(all_versions, type_members_by_version.get):
+ versioned_type_members.append((pwtms, list(versions)))
+
+ fns.append(PushWireTypesFn(
+ class_name=uclass.name,
+ versioned_type_members=versioned_type_members))
+
+ with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.c") as out:
+ util.render_template(out, "loci_push_wire_types.c", fns=fns)
+
+ with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.h") as out:
+ util.render_template(out, "loci_push_wire_types.h", fns=fns)
diff --git a/c_gen/templates/loci_push_wire_types.c b/c_gen/templates/loci_push_wire_types.c
new file mode 100644
index 0000000..2103aad
--- /dev/null
+++ b/c_gen/templates/loci_push_wire_types.c
@@ -0,0 +1,83 @@
+:: # 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.
+::
+:: include('_copyright.c')
+
+/****************************************************************
+ *
+ * Functions for each concrete class that set the type fields
+ *
+ ****************************************************************/
+
+#include <loci/loci.h>
+#include <loci/of_message.h>
+#include <endian.h>
+
+#ifdef __GNUC__
+#define UNREACHABLE() __builtin_unreachable()
+#else
+#define UNREACHABLE()
+#endif
+
+/*
+ * In a separate function to give the compiler the choice of whether to inline.
+ */
+static unsigned char *
+loci_object_to_buffer(of_object_t *obj)
+{
+ return OF_OBJECT_BUFFER_INDEX(obj, 0);
+}
+
+:: for fn in fns:
+
+void
+${fn.class_name}_push_wire_types(of_object_t *obj)
+{
+ unsigned char *buf = loci_object_to_buffer(obj);
+ switch (obj->version) {
+:: for ms, versions in fn.versioned_type_members:
+:: for version in versions:
+ case ${version.constant_version(prefix='OF_VERSION_')}:
+:: #endfor
+:: for m in ms:
+:: if m.length == 1:
+ *(uint8_t *)(buf + ${m.offset}) = ${m.value}; /* ${m.name} */
+:: elif m.length == 2:
+ *(uint16_t *)(buf + ${m.offset}) = htobe16(${m.value}); /* ${m.name} */
+:: elif m.length == 4:
+ *(uint32_t *)(buf + ${m.offset}) = htobe32(${m.value}); /* ${m.name} */
+:: else:
+:: raise("unsupported push_wire_types length %d" % m.length)
+:: #endif
+:: #endfor
+ break;
+:: #endfor
+ default:
+ UNREACHABLE();
+ }
+}
+:: #endfor
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/loci_push_wire_types.h
new file mode 100644
index 0000000..5b2c1e8
--- /dev/null
+++ b/c_gen/templates/loci_push_wire_types.h
@@ -0,0 +1,40 @@
+:: # 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.
+::
+:: include('_copyright.c')
+#ifndef LOCI_PUSH_WIRE_TYPES_H
+#define LOCI_PUSH_WIRE_TYPES_H
+
+#include <loci/loci.h>
+
+/* Declarations of public functions from loci_push_wire_types.c */
+
+:: for fn in fns:
+void ${fn.class_name}_push_wire_types(of_object_t *obj);
+:: #endfor
+
+#endif
diff --git a/lang_c.py b/lang_c.py
index 762f82c..7718d48 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -41,6 +41,7 @@
import c_gen.c_show_gen as c_show_gen
import c_gen.c_validator_gen as c_validator_gen
import c_gen.util
+import c_gen.codegen
import loxi_utils.loxi_utils as loxi_utils
import template_utils
@@ -173,3 +174,4 @@
for (name, fn) in targets.items():
with template_utils.open_output(install_dir, name) as outfile:
fn(outfile, os.path.basename(name))
+ c_gen.codegen.gen_push_wire_types(install_dir)