Example #1
0
def gen_obj_show_h(out, name):
    loxi_utils.gen_c_copy_license(out)
    out.write("""
/**
 *
 * AUTOMATICALLY GENERATED FILE.  Edits will be lost on regen.
 *
 * Header file for object showing. 
 */

/**
 * Show  object declarations
 *
 * Routines that emit a human-readable dump of each object.
 *
 */

#if !defined(_LOCI_OBJ_SHOW_H_)
#define _LOCI_OBJ_SHOW_H_

#include <loci/loci.h>
#include <stdio.h>

/* g++ requires this to pick up PRI, etc.
 * See  http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
 */
#if !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>


/**
 * Show any OF object. 
 */
int of_object_show(loci_writer_f writer, void* cookie, of_object_t* obj); 






""")

    type_to_emitter = dict(

        )
    for version in of_g.of_version_range:
        for cls in 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("""\
int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
""" % dict(cls=cls, ver_name=loxi_utils.version_to_name(version)))

    out.write("""
#endif /* _LOCI_OBJ_SHOW_H_ */
""")
Example #2
0
def gen_obj_show_h(out, name):
    loxi_utils.gen_c_copy_license(out)
    out.write("""
/**
 *
 * AUTOMATICALLY GENERATED FILE.  Edits will be lost on regen.
 *
 * Header file for object showing.
 */

/**
 * Show  object declarations
 *
 * Routines that emit a human-readable dump of each object.
 *
 */

#if !defined(_LOCI_OBJ_SHOW_H_)
#define _LOCI_OBJ_SHOW_H_

#include <loci/loci.h>
#include <stdio.h>

/* g++ requires this to pick up PRI, etc.
 * See  http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
 */
#if !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>


/**
 * Show any OF object.
 */
int of_object_show(loci_writer_f writer, void* cookie, of_object_t* obj);






""")

    type_to_emitter = dict(

        )
    for version in of_g.of_version_range:
        for cls in 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("""\
int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
""" % dict(cls=cls, ver_name=loxi_utils.version_to_name(version)))

    out.write("""
#endif /* _LOCI_OBJ_SHOW_H_ */
""")
Example #3
0
def sub_class_map(base_type, version):
    """
    Returns an iterable object giving the instance nameys and subclass types
    for the base_type, version values
    """
    rv = []
    if base_type not in inheritance_map:
        return rv

    for instance in inheritance_map[base_type]:
        subcls = loxi_utils.instance_to_class(instance, base_type)
        if not loxi_utils.class_in_version(subcls, version):
            continue
        rv.append((instance, subcls))

    return rv
Example #4
0
def sub_class_map(base_type, version):
    """
    Returns an iterable object giving the instance nameys and subclass types
    for the base_type, version values
    """
    rv = []
    if base_type not in inheritance_map:
        return rv

    for instance in inheritance_map[base_type]:
        subcls = loxi_utils.instance_to_class(instance, base_type)
        if not loxi_utils.class_in_version(subcls, version):
            continue
        rv.append((instance, subcls))

    return rv
Example #5
0
def gen_obj_show_c(out, name):
    loxi_utils.gen_c_copy_license(out)
    out.write("""
/**
 *
 * AUTOMATICALLY GENERATED FILE.  Edits will be lost on regen.
 *
 * Source file for object showing. 
 * 
 */

#define DISABLE_WARN_UNUSED_RESULT
#include <loci/loci.h>
#include <loci/loci_show.h>
#include <loci/loci_obj_show.h>

static int
unknown_show(loci_writer_f writer, void* cookie, of_object_t *obj)
{
    return writer(cookie, "Unable to print object of type %d, version %d\\n", 
                         obj->object_id, obj->version);
}    
""")

    for version in of_g.of_version_range:
        ver_name = loxi_utils.version_to_name(version)
        for cls in 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("""
int
%(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj)
{
    int out = 0;
""" % dict(cls=cls, ver_name=ver_name))

            members, member_types = loxi_utils.all_member_types_get(cls, version)
            for m_type in member_types:
                if loxi_utils.type_is_scalar(m_type) or m_type in \
                        ["of_match_t", "of_octets_t"]:
                    # Declare instance of these
                    out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
                else:
                    out.write("""
    %(m_type)s %(v_name)s;
"""  % dict(m_type=m_type, v_name=var_name_map(m_type)))
                    if loxi_utils.class_is_list(m_type):
                        base_type = loxi_utils.list_to_entry_type(m_type)
                        out.write("    %s elt;\n    int rv;\n" % base_type)
            for member in members:
                m_type = member["m_type"]
                m_name = member["name"]
                #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type)
                emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + m_name; 
                if loxi_utils.skip_member_name(m_name):
                    continue
                if (loxi_utils.type_is_scalar(m_type) or
                    m_type in ["of_match_t", "of_octets_t"]):
                    out.write("""
    %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
    out += writer(cookie, "%(m_name)s=");
    out += %(emitter)s(writer, cookie, %(v_name)s);
    out += writer(cookie, " "); 
""" % dict(cls=cls, m_name=m_name, m_type=m_type,
           v_name=var_name_map(m_type), emitter=emitter))
                elif loxi_utils.class_is_list(m_type):
                    sub_cls = m_type[:-2] # Trim _t
                    elt_type = loxi_utils.list_to_entry_type(m_type)
                    out.write("""
    out += writer(cookie, "%(elt_type)s={ ");
    %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
    %(u_type)s_ITER(&%(v_name)s, &elt, rv) {
        of_object_show(writer, cookie, (of_object_t *)&elt);
    }
    out += writer(cookie, "} "); 
""" % dict(sub_cls=sub_cls, u_type=sub_cls.upper(), v_name=var_name_map(m_type),
           elt_type=elt_type, cls=cls, m_name=m_name, m_type=m_type))
                else:
                    sub_cls = m_type[:-2] # Trim _t
                    out.write("""
    %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
    out += %(sub_cls)s_%(ver_name)s_show(writer, cookie, &%(v_name)s);
""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, 
           v_name=var_name_map(m_type), ver_name=ver_name))

            out.write("""
    return out;
}
""")
    out.write("""
/**
 * Log a match entry
 */
int
loci_show_match(loci_writer_f writer, void* cookie, of_match_t *match)
{
    int out = 0;
""")

    for key, entry in match.of_match_members.items():
        m_type = entry["m_type"]
        #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type)
        emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + key; 
        out.write("""
    if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(match)) {
        out += writer(cookie, "%(key)s active="); 
        out += %(emitter)s(writer, cookie, match->fields.%(key)s);
        out += writer(cookie, "/"); 
        out += %(emitter)s(writer, cookie, match->masks.%(key)s);
        out += writer(cookie, " ");
    }
""" % dict(key=key, ku=key.upper(), emitter=emitter, m_type=m_type))

    out.write("""
    return out;
}
""")

    # Generate big table indexed by version and object
    for version in of_g.of_version_range:
        out.write("""
static loci_obj_show_f show_funs_v%(version)s[OF_OBJECT_COUNT] = {
""" % dict(version=version))
        out.write("    unknown_show, /* of_object, not a valid specific type */\n")
        for j, cls in enumerate(of_g.all_class_order):
            comma = ""
            if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
                comma = ","

            if (not loxi_utils.class_in_version(cls, version) or 
                    cls in type_maps.inheritance_map):
                out.write("    unknown_show%s\n" % comma);
            else:
                out.write("    %s_%s_show%s\n" % 
                          (cls, loxi_utils.version_to_name(version), comma))
        out.write("};\n\n")

    out.write("""
static loci_obj_show_f *show_funs[5] = {
    NULL,
    show_funs_v1,
    show_funs_v2,
    show_funs_v3,
    show_funs_v4
};

int
of_object_show(loci_writer_f writer, void* cookie, of_object_t *obj)
{
    if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) {
        if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_2)) {
            /* @fixme VERSION */
            return show_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj);
        } else {
            return writer(cookie, "Bad version %d\\n", obj->version);
        }
    }
    return writer(cookie, "Bad object id %d\\n", obj->object_id);
}
""")
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_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;
}
""")
Example #8
0
def gen_obj_show_c(out, name):
    loxi_utils.gen_c_copy_license(out)
    out.write("""
/**
 *
 * AUTOMATICALLY GENERATED FILE.  Edits will be lost on regen.
 *
 * Source file for object showing.
 *
 */

#define DISABLE_WARN_UNUSED_RESULT
#include <loci/loci.h>
#include <loci/loci_show.h>
#include <loci/loci_obj_show.h>

static int
unknown_show(loci_writer_f writer, void* cookie, of_object_t *obj)
{
    return writer(cookie, "Unable to print object of type %d, version %d\\n",
                         obj->object_id, obj->version);
}
""")

    for version in of_g.of_version_range:
        ver_name = loxi_utils.version_to_name(version)
        for cls in of_g.standard_class_order:
            if not loxi_utils.class_in_version(cls, version):
                continue
            if type_maps.class_is_virtual(cls):
                continue
            out.write("""
int
%(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, of_object_t *obj)
{
    int out = 0;
""" % dict(cls=cls, ver_name=ver_name))

            members, member_types = loxi_utils.all_member_types_get(cls, version)
            for m_type in member_types:
                if loxi_utils.type_is_scalar(m_type) or m_type in \
                        ["of_match_t", "of_octets_t"]:
                    # Declare instance of these
                    out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
                else:
                    out.write("""
    %(m_type)s %(v_name)s;
"""  % dict(m_type=m_type, v_name=var_name_map(m_type)))
                    if loxi_utils.class_is_list(m_type):
                        out.write("    of_object_t elt;\n    int rv;\n")
            for member in members:
                m_type = member["m_type"]
                m_name = member["name"]
                emitter = gen_emitter(cls, m_name, m_type)
                if loxi_utils.skip_member_name(m_name):
                    continue
                if (loxi_utils.type_is_scalar(m_type) or
                    m_type in ["of_match_t", "of_octets_t"]):
                    out.write("""
    %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
    out += writer(cookie, "%(m_name)s=");
    out += %(emitter)s(writer, cookie, %(v_name)s);
    out += writer(cookie, " ");
""" % dict(cls=cls, m_name=m_name, m_type=m_type,
           v_name=var_name_map(m_type), emitter=emitter))
                elif loxi_utils.class_is_list(m_type):
                    sub_cls = m_type[:-2] # Trim _t
                    elt_type = loxi_utils.list_to_entry_type(m_type)
                    out.write("""
    out += writer(cookie, "%(elt_type)s={ ");
    %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
    %(u_type)s_ITER(&%(v_name)s, &elt, rv) {
        of_object_show(writer, cookie, (of_object_t *)&elt);
    }
    out += writer(cookie, "} ");
""" % dict(sub_cls=sub_cls, u_type=sub_cls.upper(), v_name=var_name_map(m_type),
           elt_type=elt_type, cls=cls, m_name=m_name, m_type=m_type))
                else:
                    sub_cls = m_type[:-2] # Trim _t
                    out.write("""
    %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
    out += of_object_show(writer, cookie, &%(v_name)s);
""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name,
           v_name=var_name_map(m_type), ver_name=ver_name))

            out.write("""
    return out;
}
""")
    out.write("""
/**
 * Log a match entry
 */
int
loci_show_match(loci_writer_f writer, void* cookie, of_match_t *match)
{
    int out = 0;
""")

    for key, entry in match.of_match_members.items():
        m_type = entry["m_type"]
        emitter = gen_emitter('of_match', key, m_type)
        out.write("""
    if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(match)) {
        out += writer(cookie, "%(key)s active=");
        out += %(emitter)s(writer, cookie, match->fields.%(key)s);
        out += writer(cookie, "/");
        out += %(emitter)s(writer, cookie, match->masks.%(key)s);
        out += writer(cookie, " ");
    }
""" % dict(key=key, ku=key.upper(), emitter=emitter, m_type=m_type))

    out.write("""
    return out;
}
""")

    # Generate big table indexed by version and object
    for version in of_g.of_version_range:
        out.write("""
static const loci_obj_show_f show_funs_v%(version)s[OF_OBJECT_COUNT] = {
""" % dict(version=version))
        out.write("    unknown_show, /* of_object, not a valid specific type */\n")
        for j, cls in enumerate(of_g.all_class_order):
            comma = ""
            if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
                comma = ","

            if (not loxi_utils.class_in_version(cls, version) or
                    type_maps.class_is_virtual(cls)):
                out.write("    unknown_show%s\n" % comma);
            else:
                out.write("    %s_%s_show%s\n" %
                          (cls, loxi_utils.version_to_name(version), comma))
        out.write("};\n\n")

    out.write("""
static const loci_obj_show_f *const show_funs[] = {
""")

    for version in of_g.of_version_range:
        out.write("    [%(v)d] = show_funs_v%(v)d,\n" % dict(v=version))

    out.write("""\
};

int
of_object_show(loci_writer_f writer, void* cookie, of_object_t *obj)
{
    if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) {
        if (OF_VERSION_OKAY(obj->version)) {
            return show_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj);
        } else {
            return writer(cookie, "Bad version %d\\n", obj->version);
        }
    }
    return writer(cookie, "Bad object id %d\\n", obj->object_id);
}
""")
Example #9
0
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))
Example #10
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;
}
""")