Initial import
LoxiGen is the work of several developers, not just myself.
diff --git a/c_gen/c_validator_gen.py b/c_gen/c_validator_gen.py
new file mode 100644
index 0000000..3ab6acf
--- /dev/null
+++ b/c_gen/c_validator_gen.py
@@ -0,0 +1,302 @@
+# 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.
+
+"""
+@brief Validator function generation
+
+Generates validator function files.
+
+"""
+
+import sys
+import of_g
+import loxi_front_end.match as match
+import loxi_front_end.flags as flags
+from generic_utils import *
+import loxi_front_end.type_maps as type_maps
+import loxi_utils.loxi_utils as loxi_utils
+import loxi_front_end.identifiers as identifiers
+from c_test_gen import var_name_map
+
+def gen_h(out, name):
+ loxi_utils.gen_c_copy_license(out)
+ out.write("""
+/**
+ *
+ * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
+ *
+ * Declarations of message validation functions. These functions check that an
+ * OpenFlow message is well formed. Specifically, they check internal length
+ * fields.
+ */
+
+#if !defined(_LOCI_VALIDATOR_H_)
+#define _LOCI_VALIDATOR_H_
+
+#include <loci/loci.h>
+
+/*
+ * Validate an OpenFlow message.
+ * @return 0 if message is valid, -1 otherwise.
+ */
+extern int of_validate_message(of_message_t msg, int len);
+
+#endif /* _LOCI_VALIDATOR_H_ */
+""")
+
+def gen_c(out, name):
+ loxi_utils.gen_c_copy_license(out)
+ out.write("""
+/**
+ *
+ * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
+ *
+ * Source file for OpenFlow message validation.
+ *
+ */
+
+#include "loci_log.h"
+#include <loci/loci.h>
+#include <loci/loci_validator.h>
+
+#define VALIDATOR_LOG(...) LOCI_LOG_ERROR("Validator Error: " __VA_ARGS__)
+
+""")
+
+ # Declarations
+ for version in of_g.of_version_range:
+ ver_name = loxi_utils.version_to_name(version)
+ for cls in reversed(of_g.standard_class_order):
+ if not loxi_utils.class_in_version(cls, version):
+ continue
+ if cls in type_maps.inheritance_map:
+ continue
+ out.write("""
+static inline int %(cls)s_%(ver_name)s_validate(uint8_t *buf, int len);\
+""" % dict(cls=cls, ver_name=ver_name))
+
+ out.write("\n")
+
+ # Definitions
+ for version in of_g.of_version_range:
+ ver_name = loxi_utils.version_to_name(version)
+ for cls in reversed(of_g.standard_class_order):
+ if not loxi_utils.class_in_version(cls, version):
+ continue
+ if cls in type_maps.inheritance_map:
+ continue
+ if loxi_utils.class_is_list(cls):
+ gen_list_validator(out, cls, version)
+ else:
+ gen_validator(out, cls, version)
+
+ out.write("""
+int
+of_validate_message_%(ver_name)s(of_message_t msg, int len)
+{
+ of_object_id_t object_id = of_message_to_object_id(msg, len);
+ uint8_t *buf = OF_MESSAGE_TO_BUFFER(msg);
+ switch (object_id) {
+""" % dict(ver_name=ver_name))
+ for cls in reversed(of_g.standard_class_order):
+ if not loxi_utils.class_in_version(cls, version):
+ continue
+ if cls in type_maps.inheritance_map:
+ continue
+ if loxi_utils.class_is_message(cls):
+ out.write("""\
+ case %(cls_id)s:
+ return %(cls)s_%(ver_name)s_validate(buf, len);
+""" % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper()))
+ out.write("""\
+ default:
+ VALIDATOR_LOG("%(cls)s: could not map %(cls_id)s");
+ return -1;
+ }
+}
+""" % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper()))
+
+ out.write("""
+int
+of_validate_message(of_message_t msg, int len)
+{
+ of_version_t version;
+ if (len < OF_MESSAGE_MIN_LENGTH ||
+ len != of_message_length_get(msg)) {
+ VALIDATOR_LOG("message length %d != %d", len,
+ of_message_length_get(msg));
+ return -1;
+ }
+
+ version = of_message_version_get(msg);
+ switch (version) {
+""")
+
+ for version in of_g.of_version_range:
+ ver_name = loxi_utils.version_to_name(version)
+ out.write("""\
+ case %(ver_name)s:
+ return of_validate_message_%(ver_name)s(msg, len);
+""" % dict(ver_name=ver_name))
+
+ out.write("""\
+ default:
+ VALIDATOR_LOG("Bad version %%d", %(ver_name)s);
+ return -1;
+ }
+}
+""" % dict(ver_name=ver_name))
+
+def gen_validator(out, cls, version):
+ fixed_len = of_g.base_length[(cls, version)];
+ ver_name = loxi_utils.version_to_name(version)
+ out.write("""
+static inline int
+%(cls)s_%(ver_name)s_validate(uint8_t *buf, int len)
+{
+ if (len < %(fixed_len)s) {
+ VALIDATOR_LOG("Class %(cls)s. Len %%d too small, < %%d", len, %(fixed_len)s);
+ return -1;
+ }
+""" % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), fixed_len=fixed_len))
+ members, member_types = loxi_utils.all_member_types_get(cls, version)
+ for member in members:
+ m_type = member["m_type"]
+ m_name = member["name"]
+ m_offset = member['offset']
+ m_cls = m_type[:-2] # Trim _t
+ if loxi_utils.skip_member_name(m_name):
+ continue
+ if not loxi_utils.type_is_of_object(m_type):
+ continue
+ if not loxi_utils.class_is_var_len(m_cls, version):
+ continue
+ if cls == "of_packet_out" and m_name == "actions":
+ # See _PACKET_OUT_ACTION_LEN
+ out.write("""
+ {
+ uint16_t %(m_name)s_len;
+ buf_u16_get(buf + %(m_offset)s - 2, &%(m_name)s_len);
+ if (%(m_name)s_len + %(m_offset)s > len) {
+ VALIDATOR_LOG("Class %(cls)s, member %(m_name)s. "
+ "Len %%d and offset %%d too big for %%d",
+ %(m_name)s_len, %(m_offset)s, len);
+ return -1;
+ }
+""" % dict(m_name=m_name, m_offset=m_offset, cls=cls))
+ else:
+ out.write("""
+
+ { int %(m_name)s_len = len - %(m_offset)s;
+
+""" % dict(m_name=m_name, m_offset=m_offset))
+ out.write("""
+ if (%(m_cls)s_%(ver_name)s_validate(buf + %(m_offset)s, %(m_name)s_len) < 0) {
+ return -1;
+ }
+ }
+""" % dict(m_name=m_name, m_cls=m_cls, ver_name=ver_name, m_offset=m_offset))
+ out.write("""
+ return 0;
+}
+""")
+
+def gen_list_validator(out, cls, version):
+ ver_name = loxi_utils.version_to_name(version)
+ e_cls = loxi_utils.list_to_entry_type(cls)
+ fixed_len = of_g.base_length[(e_cls, version)];
+ out.write("""
+static inline int
+%(cls)s_%(ver_name)s_validate(uint8_t *buf, int len)
+{
+""" % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), e_cls=e_cls))
+
+ # TLV16
+ if loxi_utils.class_is_tlv16(e_cls):
+ subclasses = type_maps.inheritance_map[e_cls]
+ out.write("""\
+ while (len >= %(fixed_len)s) {
+ of_object_id_t e_id;
+ uint16_t e_type, e_len;
+ buf_u16_get(buf, &e_type);
+ buf_u16_get(buf+2, &e_len);
+ e_id = %(e_cls)s_to_object_id(e_type, %(ver_name)s);
+ switch (e_id) {
+""" % dict(fixed_len=fixed_len, ver_name=ver_name, e_cls=e_cls))
+ for subcls in subclasses:
+ subcls = e_cls + '_' + subcls
+ if not loxi_utils.class_in_version(subcls, version):
+ continue
+ out.write("""\
+ case %(subcls_enum)s:
+ if (%(subcls)s_%(ver_name)s_validate(buf, e_len) < 0) {
+ return -1;
+ }
+ break;
+""" % dict(ver_name=ver_name, subcls=subcls, subcls_enum=loxi_utils.enum_name(subcls)))
+ out.write("""\
+ default:
+ return -1;
+ }
+ buf += e_len;
+ len -= e_len;
+ }
+ if (len != 0) {
+ return -1;
+ }
+""" % dict(e_cls=e_cls, ver_name=ver_name))
+
+ # U16 len
+ elif loxi_utils.class_is_u16_len(e_cls) or loxi_utils.class_is_action(e_cls):
+ out.write("""\
+ /* TODO verify U16 len elements */
+""" % dict())
+
+ # OXM
+ elif loxi_utils.class_is_oxm(e_cls):
+ out.write("""\
+ /* TODO verify OXM elements */
+""" % dict())
+
+ # Fixed length
+ elif not loxi_utils.class_is_var_len(e_cls, version):
+ out.write("""\
+ if ((len / %(fixed_len)s) * %(fixed_len)s != len) {
+ return -1;
+ }
+""" % dict(fixed_len=fixed_len))
+
+ # ???
+ else:
+ out.write("""\
+ /* XXX unknown element format */
+""" % dict())
+
+ out.write("""
+ return 0;
+}
+""")