blob: d4525ba1d7f85c4ec3608d35eb5d9bf9ba1ad25f [file] [log] [blame]
# 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 C code generation for LOXI type related maps
#
import c_gen.of_g_legacy as of_g
import sys
from generic_utils import *
import c_gen.type_maps as type_maps
# Some number larger than small type values, but less then
# reserved values like 0xffff
max_type_value = 1000
def gen_type_to_object_id(out, type_str, prefix, template,
value_array, max_val):
"""
Generate C maps from various message class groups to object ids
For each version, create an array mapping the type info to the
object ID. Then define an array containing those pointers.
"""
# Create unified arrays and get length
arr_len = type_maps.type_array_len(value_array, max_val)
all_ars = []
for version, val_dict in value_array.items(): # Per version dict
ar = type_maps.dict_to_array(val_dict, max_val, type_maps.invalid_type)
all_ars.append(ar)
len_name = "%s_ITEM_COUNT" % prefix
for i, ar in enumerate(all_ars):
version = i + 1
out.write("static const of_object_id_t\nof_%s_v%d[%s] = {\n" %
(type_str, version, len_name))
for i in range(arr_len):
comma = ""
if i < arr_len - 1: # Avoid ultimate comma
comma = ","
# Per-version length check
if i < len(ar):
v = ar[i]
else:
v = type_maps.invalid_type
if v == type_maps.invalid_type:
out.write(" %-30s /* %d (Invalid) */\n" %
("OF_OBJECT_INVALID" + comma, i))
else:
name = (template % v.upper()) + comma
out.write(" %-30s /* %d */\n" % (name, i))
out.write("};\n")
out.write("""
/**
* Maps from %(c_name)s wire type values to LOCI object ids
*
* Indexed by wire version which is 1-based.
*/
const of_object_id_t *const of_%(name)s[OF_VERSION_ARRAY_MAX] = {
NULL,
""" % dict(name=type_str, c_name=prefix.lower()))
for version in of_g.of_version_range:
out.write(" of_%(name)s_v%(version)d,\n" % dict(name=type_str,
version=version))
out.write("""
};
""" % dict(name=type_str, u_name=type_str.upper(),
max_val=max_val, c_name=prefix.lower()))
def gen_type_maps(out):
"""
Generate various type maps
@param out The file handle to write to
"""
# Generate maps from wire type values to object IDs
gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
"OF_%s_ERROR_MSG", type_maps.error_types,
max_type_value)
gen_type_to_object_id(out, "action_type_to_id", "OF_ACTION",
"OF_ACTION_%s", type_maps.action_types,
max_type_value)
gen_type_to_object_id(out, "action_id_type_to_id", "OF_ACTION_ID",
"OF_ACTION_ID_%s", type_maps.action_id_types,
max_type_value)
gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
"OF_INSTRUCTION_%s", type_maps.instruction_types,
max_type_value)
gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
"OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
max_type_value)
gen_type_to_object_id(out, "table_feature_prop_type_to_id",
"OF_TABLE_FEATURE_PROP",
"OF_TABLE_FEATURE_PROP_%s",
type_maps.table_feature_prop_types,
max_type_value)
gen_type_to_object_id(out, "meter_band_type_to_id", "OF_METER_BAND",
"OF_METER_BAND_%s", type_maps.meter_band_types,
max_type_value)
gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
"OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
max_type_value)
gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
"OF_GROUP_%s", type_maps.group_mod_types,
max_type_value)
# FIXME: Multipart re-organization
gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
"OF_%s_STATS_REQUEST", type_maps.stats_types,
max_type_value)
gen_type_to_object_id(out, "stats_reply_type_to_id", "OF_STATS_REPLY",
"OF_%s_STATS_REPLY", type_maps.stats_types,
max_type_value)
gen_type_to_object_id(out, "flow_mod_type_to_id", "OF_FLOW_MOD",
"OF_FLOW_%s", type_maps.flow_mod_types,
max_type_value)
gen_type_to_object_id(out, "oxm_type_to_id", "OF_OXM",
"OF_OXM_%s", type_maps.oxm_types, max_type_value)
gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
"OF_%s", type_maps.message_types, max_type_value)
gen_type_to_object_id(out, "bsn_tlv_type_to_id", "OF_BSN_TLV",
"OF_BSN_TLV_%s", type_maps.bsn_tlv_types,
max_type_value)
def gen_type_to_obj_map_functions(out):
"""
Generate the templated type map functions
@param out The file handle to write to
"""
################################################################
# Generate all type-to-object-ID maps in a common way
################################################################
map_template = """
/**
* %(name)s wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
/**
* Map an %(name)s wire value to an OF object
* @param %(name)s The %(name)s type wire value
* @param version The version associated with the check
* @return The %(name)s OF object type
* @return OF_OBJECT_INVALID if type does not map to an object
*
*/
of_object_id_t
of_%(name)s_to_object_id(int %(name)s, of_version_t version)
{
if (!OF_VERSION_OKAY(version)) {
return OF_OBJECT_INVALID;
}
if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
return of_%(name)s_type_to_id[version][%(name)s];
}
"""
map_with_experimenter_template = """
/**
* %(name)s wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
/**
* Map an %(name)s wire value to an OF object
* @param %(name)s The %(name)s type wire value
* @param version The version associated with the check
* @return The %(name)s OF object type
* @return OF_OBJECT_INVALID if type does not map to an object
*
*/
of_object_id_t
of_%(name)s_to_object_id(int %(name)s, of_version_t version)
{
if (!OF_VERSION_OKAY(version)) {
return OF_OBJECT_INVALID;
}
if (%(name)s == OF_EXPERIMENTER_TYPE) {
return OF_%(u_name)s_EXPERIMENTER;
}
if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
return of_%(name)s_type_to_id[version][%(name)s];
}
"""
stats_template = """
/**
* %(name)s wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
/**
* Map an %(name)s wire value to an OF object
* @param %(name)s The %(name)s type wire value
* @param version The version associated with the check
* @return The %(name)s OF object type
* @return OF_OBJECT_INVALID if type does not map to an object
*
*/
of_object_id_t
of_%(name)s_to_object_id(int %(name)s, of_version_t version)
{
if (!OF_VERSION_OKAY(version)) {
return OF_OBJECT_INVALID;
}
if (%(name)s == OF_EXPERIMENTER_TYPE) {
return OF_EXPERIMENTER_%(u_name)s;
}
if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
return of_%(name)s_type_to_id[version][%(name)s];
}
"""
error_msg_template = """
/**
* %(name)s wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
/**
* Map an %(name)s wire value to an OF object
* @param %(name)s The %(name)s type wire value
* @param version The version associated with the check
* @return The %(name)s OF object type
* @return OF_OBJECT_INVALID if type does not map to an object
*
*/
of_object_id_t
of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
{
if (!OF_VERSION_OKAY(version)) {
return OF_OBJECT_INVALID;
}
if (%(name)s == OF_EXPERIMENTER_TYPE) {
return OF_EXPERIMENTER_ERROR_MSG;
}
if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
return of_%(name)s_type_to_id[version][%(name)s];
}
"""
# Experimenter mapping functions
# Currently we support very few candidates, so we just do a
# list of if/elses
experimenter_function = """
/**
* @brief Map a message known to be an exp msg to the proper object
*
* Assume that the message is a vendor/experimenter message. Determine
* the specific object type for the message.
* @param msg An OF message object (uint8_t *)
* @param length The number of bytes in the message (for error checking)
* @param version Version of message
* @returns object ID of specific type if recognized or OF_EXPERIMENTER if not
*
* @todo put OF_EXPERIMENTER_<name> in loci_base.h
*/
of_object_id_t
of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
uint32_t experimenter_id;
uint32_t subtype;
/* Extract experimenter and subtype value; look for match from type maps */
experimenter_id = of_message_experimenter_id_get(msg);
subtype = of_message_experimenter_subtype_get(msg);
/* Do a simple if/else search for the ver, experimenter and subtype */
"""
first = True
for version, experimenter_lists in type_maps.extension_message_subtype.items():
for exp, subtypes in experimenter_lists.items():
experimenter_function += """
if ((experimenter_id == OF_EXPERIMENTER_ID_%(exp_name)s) &&
(version == %(ver_name)s)) {
""" % dict(exp_name=exp.upper(), ver_name=of_g.wire_ver_map[version])
for ext_msg, subtype in subtypes.items():
experimenter_function += """
if (subtype == %(subtype)s) {
return %(ext_msg)s;
}
""" % dict(subtype=subtype, ext_msg=ext_msg.upper())
experimenter_function += """
}
"""
experimenter_function += """
return OF_EXPERIMENTER;
}
"""
# Message need different handling
msg_template = """
/**
* %(name)s wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
/**
* Extract the type info from the message and determine its object type
* @param msg An OF message object (uint8_t *)
* @param length The number of bytes in the message (for error checking)
* @returns object ID or OF_OBJECT_INVALID if parse error
*/
of_object_id_t
of_message_to_object_id(of_message_t msg, int length) {
uint8_t type;
of_version_t ver;
of_object_id_t obj_id;
uint16_t stats_type;
uint16_t err_type;
uint8_t flow_mod_cmd;
uint32_t experimenter, subtype;
uint16_t group_mod_cmd;
if (length < OF_MESSAGE_MIN_LENGTH) {
return OF_OBJECT_INVALID;
}
type = of_message_type_get(msg);
ver = of_message_version_get(msg);
if (!OF_VERSION_OKAY(ver)) {
return OF_OBJECT_INVALID;
}
if (type >= OF_MESSAGE_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
obj_id = of_message_type_to_id[ver][type];
/* Remap to specific message if known */
if (obj_id == OF_EXPERIMENTER) {
if (length < OF_MESSAGE_EXPERIMENTER_MIN_LENGTH) {
return OF_OBJECT_INVALID;
}
return of_message_experimenter_to_object_id(msg, ver);
}
/* Remap to add/delete/strict version */
if (obj_id == OF_FLOW_MOD) {
if (length < OF_MESSAGE_MIN_FLOW_MOD_LENGTH(ver)) {
return OF_OBJECT_INVALID;
}
flow_mod_cmd = of_message_flow_mod_command_get(msg, ver);
obj_id = of_flow_mod_to_object_id(flow_mod_cmd, ver);
}
if ((obj_id == OF_STATS_REQUEST) || (obj_id == OF_STATS_REPLY)) {
if (length < OF_MESSAGE_MIN_STATS_LENGTH) {
return OF_OBJECT_INVALID;
}
stats_type = of_message_stats_type_get(msg);
if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
return OF_OBJECT_INVALID;
}
experimenter = of_message_stats_experimenter_id_get(msg);
subtype = of_message_stats_experimenter_subtype_get(msg);
if (obj_id == OF_STATS_REQUEST) {
obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
} else {
obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
}
} else {
if (obj_id == OF_STATS_REQUEST) {
obj_id = of_stats_request_to_object_id(stats_type, ver);
} else {
obj_id = of_stats_reply_to_object_id(stats_type, ver);
}
}
}
if (obj_id == OF_ERROR_MSG) {
if (length < OF_MESSAGE_MIN_ERROR_LENGTH) {
return OF_OBJECT_INVALID;
}
err_type = of_message_error_type_get(msg);
obj_id = of_error_msg_to_object_id(err_type, ver);
}
if (obj_id == OF_GROUP_MOD) {
if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
return OF_OBJECT_INVALID;
}
group_mod_cmd = of_message_group_mod_command_get(msg);
obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
}
return obj_id;
}
"""
oxm_template = """
/**
* oxm wire type to object ID array.
* Treat as private; use function accessor below
*/
extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
#define OF_OXM_ITEM_COUNT %(ar_len)d\n
/**
* Map an oxm wire value to an OF object
* @param oxm The oxm type wire value
* @param version The version associated with the check
* @return The oxm OF object type
* @return OF_OBJECT_INVALID if type does not map to an object
*
*/
of_object_id_t
of_oxm_to_object_id(uint32_t type_len, of_version_t version)
{
if (!OF_VERSION_OKAY(version)) {
return OF_OBJECT_INVALID;
}
uint16_t class = (type_len >> 16) & 0xffff;
uint8_t masked_type = (type_len >> 8) & 0xff;
if (class == 0x8000) {
if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
return OF_OBJECT_INVALID;
}
return of_oxm_type_to_id[version][masked_type];
} else if (class == 0x0003) {
switch (masked_type) {
case 0x00: return OF_OXM_BSN_IN_PORTS_128;
case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
case 0x02: return OF_OXM_BSN_LAG_ID;
case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
case 0x04: return OF_OXM_BSN_VRF;
case 0x05: return OF_OXM_BSN_VRF_MASKED;
case 0x06: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED;
case 0x07: return OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED;
case 0x08: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID;
case 0x09: return OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED;
case 0x0a: return OF_OXM_BSN_L3_SRC_CLASS_ID;
case 0x0b: return OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED;
case 0x0c: return OF_OXM_BSN_L3_DST_CLASS_ID;
case 0x0d: return OF_OXM_BSN_L3_DST_CLASS_ID_MASKED;
default: return OF_OBJECT_INVALID;
}
} else {
return OF_OBJECT_INVALID;
}
}
"""
# Action types array gen
ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
out.write(map_with_experimenter_template %
dict(name="action", u_name="ACTION", ar_len=ar_len))
# Action ID types array gen
ar_len = type_maps.type_array_len(type_maps.action_id_types, max_type_value)
out.write(map_with_experimenter_template %
dict(name="action_id", u_name="ACTION_ID", ar_len=ar_len))
# Instruction types array gen
ar_len = type_maps.type_array_len(type_maps.instruction_types,
max_type_value)
out.write(map_with_experimenter_template %
dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
# Queue prop types array gen
ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
max_type_value)
out.write(map_with_experimenter_template %
dict(name="queue_prop", u_name="QUEUE_PROP", ar_len=ar_len))
# Table feature prop types array gen
ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
max_type_value)
out.write(map_with_experimenter_template %
dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
ar_len=ar_len))
# Meter band types array gen
ar_len = type_maps.type_array_len(type_maps.meter_band_types,
max_type_value)
out.write(map_with_experimenter_template %
dict(name="meter_band", u_name="METER_BAND", ar_len=ar_len))
# Hello elem types array gen
ar_len = type_maps.type_array_len(type_maps.hello_elem_types,
max_type_value)
out.write(map_template %
dict(name="hello_elem", u_name="HELLO_ELEM", ar_len=ar_len))
# Stats types array gen
ar_len = type_maps.type_array_len(type_maps.stats_types,
max_type_value)
out.write(stats_template %
dict(name="stats_reply", u_name="STATS_REPLY", ar_len=ar_len))
out.write(stats_template %
dict(name="stats_request", u_name="STATS_REQUEST",
ar_len=ar_len))
ar_len = type_maps.type_array_len(type_maps.error_types,
max_type_value)
out.write(error_msg_template %
dict(name="error_msg", u_name="ERROR_MSG", ar_len=ar_len))
# out.write(error_msg_function)
ar_len = type_maps.type_array_len(type_maps.flow_mod_types, max_type_value)
out.write(map_template %
dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
ar_len = type_maps.type_array_len(type_maps.group_mod_types,
max_type_value)
out.write(map_template %
dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
# OXM
ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
out.write("""
/* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
""")
out.write(oxm_template % dict(ar_len=ar_len))
# Messages
out.write(experimenter_function)
# Must follow stats reply/request
ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
out.write(msg_template %
dict(name="message", u_name="MESSAGE", ar_len=ar_len))
# BSN TLV elem types array gen
ar_len = type_maps.type_array_len(type_maps.bsn_tlv_types,
max_type_value)
out.write(map_template %
dict(name="bsn_tlv", u_name="BSN_TLV", ar_len=ar_len))
def gen_type_data_header(out):
out.write("""
/****************************************************************
*
* The following declarations are for type and length calculations.
* Implementations may be found in of_type_maps.c
*
****************************************************************/
/*
* Special case length functions for objects with
*/
""")
for ((cls, name), prev) in of_g.special_offsets.items():
s_cls = cls[3:] # take off of_
out.write("""
/**
* Special length calculation for %(cls)s->%(name)s.
* @param obj An object of type %(cls)s to check for
* length of %(name)s
* @param bytes[out] Where to store the calculated length
*
* Preceding data member is %(prev)s.
*/
extern int of_length_%(s_cls)s_%(name)s_get(
%(cls)s_t *obj, int *bytes);
/**
* Special offset calculation for %(cls)s->%(name)s.
* @param obj An object of type %(cls)s to check for
* length of %(name)s
* @param offset[out] Where to store the calculated length
*
* Preceding data member is %(prev)s.
*/
extern int of_offset_%(s_cls)s_%(name)s_get(
%(cls)s_t *obj, int *offset);
""" % dict(cls=cls, s_cls=s_cls, name=name, prev=prev))
# NOT NEEDED YET
# # For non-message, variable length objects, give a fun that
# # calculates the length
# for cls in of_g.standard_class_order:
# s_cls = cls[3:] # take off of_
# if !type_is_var_len(cls, version):
# continue
# out.write("""
# /**
# * Special length calculation for variable length object %(cls)s
# * @param obj An object of type %(cls)s whose length is being calculated
# * @param bytes[out] Where to store the calculated length
# *
# * The assumption is that the length member of the object is not
# * valid and the length needs to be calculated from other information
# * such as the parent.
# */
# extern int of_length_%(s_cls)s_get(
# %(cls)s_t *obj, int *bytes);
# """ % dict(cls=cls, s_cls=s_cls))
out.write("""
/****************************************************************
* Wire type/length functions.
****************************************************************/
extern void of_object_message_wire_length_get(of_object_t *obj, int *bytes);
extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
/* Wire length is uint16 at front of structure */
extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
extern void of_action_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
extern void of_instruction_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_meter_band_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_bsn_tlv_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
#define OF_OXM_LENGTH_SET(hdr, val) \\
(hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
extern void of_list_meter_band_stats_wire_length_get(of_object_t *obj,
int *bytes);
extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
extern int of_extension_object_wire_push(of_object_t *obj);
""")
def gen_length_array(out):
"""
Generate an array giving the lengths of all objects/versions
@param out The file handle to which to write
"""
out.write("""
/**
* An array with the number of bytes in the fixed length part
* of each OF object
*/
""")
for version in of_g.of_version_range:
out.write("""
static const int\nof_object_fixed_len_v%d[OF_OBJECT_COUNT] = {
-1, /* of_object is not instantiable */
""" % version)
for i, cls in enumerate(of_g.all_class_order):
comma = ","
if i == len(of_g.all_class_order) - 1:
comma = ""
val = "-1" + comma
if (cls, version) in of_g.base_length:
val = str(of_g.base_length[(cls, version)]) + comma
out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
out.write("};\n")
out.write("""
/**
* Unified map of fixed length part of each object
*/
const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX] = {
NULL,
""")
for version in of_g.of_version_range:
out.write(" of_object_fixed_len_v%d,\n" % version)
out.write("""
};
""")
def gen_extra_length_array(out):
"""
Generate an array giving the extra lengths of all objects/versions
@param out The file handle to which to write
"""
out.write("""
/**
* An array with the number of bytes in the extra length part
* of each OF object
*/
""")
for version in of_g.of_version_range:
out.write("""
static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
-1, /* of_object is not instantiable */
""" % version)
for i, cls in enumerate(of_g.all_class_order):
comma = ","
if i == len(of_g.all_class_order) - 1:
comma = ""
val = "-1" + comma
if (cls, version) in of_g.base_length:
val = str(of_g.extra_length.get((cls, version), 0)) + comma
out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
out.write("};\n")
out.write("""
/**
* Unified map of extra length part of each object
*/
const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
NULL,
""")
for version in of_g.of_version_range:
out.write(" of_object_extra_len_v%d,\n" % version)
out.write("""
};
""")