Merge into master from pull request #326:
LOCI cleanup (https://github.com/floodlight/loxigen/pull/326)
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 9b19af6..047b254 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -361,81 +361,6 @@
"""
Use the type members in the IR to fill out the legacy type_maps.
"""
-
- def split_inherited_cls(cls):
- if cls == 'of_meter_band_stats': # HACK not a subtype of of_meter_band
- return None, None
- for parent in sorted(type_maps.inheritance_data.keys(), reverse=True):
- if cls.startswith(parent):
- return (parent, cls[len(parent)+1:])
- return None, None
-
- def find_experimenter(parent, cls):
- for experimenter in sorted(of_g.experimenter_name_to_id.keys(), reverse=True):
- prefix = parent + '_' + experimenter
- if cls.startswith(prefix) and cls != prefix:
- return experimenter
- return None
-
- def find_type_value(ofclass, m_name):
- for m in ofclass.members:
- if isinstance(m, OFTypeMember) and m.name == m_name:
- return m.value
- raise KeyError("ver=%d, cls=%s, m_name=%s" % (wire_version, cls, m_name))
-
- # Most inheritance classes: actions, instructions, etc
- for version, protocol in loxi_globals.ir.items():
- wire_version = version.wire_version
- for ofclass in protocol.classes:
- cls = ofclass.name
- parent, subcls = split_inherited_cls(cls)
- if not (parent and subcls):
- continue
- if parent == 'of_oxm':
- type_len = find_type_value(ofclass, 'type_len')
- oxm_class = (type_len >> 16) & 0xffff
- if oxm_class != 0x8000:
- # Do not include experimenter OXMs in the main table
- val = type_maps.invalid_type
- else:
- val = (type_len >> 8) & 0xff
- else:
- val = find_type_value(ofclass, 'type')
- type_maps.inheritance_data[parent][wire_version][subcls] = val
-
- # Extensions (only actions for now)
- experimenter = find_experimenter(parent, cls)
- if parent == 'of_action' and experimenter:
- val = find_type_value(ofclass, 'subtype')
- type_maps.extension_action_subtype[wire_version][experimenter][cls] = val
- if wire_version >= of_g.VERSION_1_3:
- cls2 = parent + "_id" + cls[len(parent):]
- type_maps.extension_action_id_subtype[wire_version][experimenter][cls2] = val
- elif parent == 'of_instruction' and experimenter:
- val = find_type_value(ofclass, 'subtype')
- type_maps.extension_instruction_subtype[wire_version][experimenter][cls] = val
-
- # Messages
- for version, protocol in loxi_globals.ir.items():
- wire_version = version.wire_version
- for ofclass in protocol.classes:
- cls = ofclass.name
- # HACK (though this is what loxi_utils.class_is_message() does)
- if not [x for x in ofclass.members if isinstance(x, OFDataMember) and x.name == 'xid']:
- continue
- if type_maps.class_is_virtual(cls):
- continue
- subcls = cls[3:]
- val = find_type_value(ofclass, 'type')
- if not val in type_maps.message_types[wire_version].values():
- type_maps.message_types[wire_version][subcls] = val
-
- # Extensions
- experimenter = find_experimenter('of', cls)
- if experimenter and ofclass.is_subclassof("of_experimenter"):
- val = find_type_value(ofclass, 'subtype')
- type_maps.extension_message_subtype[wire_version][experimenter][cls] = val
-
type_maps.generate_maps()
def analyze_input():
@@ -448,7 +373,7 @@
for wire_version, ordered_classes in of_g.ordered_classes.items():
classes = versions[of_g.of_version_wire2name[wire_version]]['classes']
for cls in ordered_classes:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
new_cls = cls + '_header'
of_g.ordered_classes[wire_version].append(new_cls)
classes[new_cls] = classes[cls]
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 6556d3b..3229403 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -874,61 +874,6 @@
#define OF_MESSAGE_OBJECT_COUNT %d
""" % ((last + 1), msg_count))
- # Generate object type range checking for inheritance classes
-
- # @fixme These should be determined algorithmicly
- out.write("""
-/*
- * Macros to check if an object ID is within an inheritance class range
- */
-""")
- # Alphabetical order for 'last'
- last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
- of_oxm="OF_OXM_VLAN_VID_MASKED",
- of_instruction="OF_INSTRUCTION_WRITE_METADATA",
- of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
- of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
- # @FIXME add meter_band ?
- )
- for cls, last in last_ids.items():
- out.write("""
-#define %(enum)s_FIRST_ID (%(enum)s + 1)
-#define %(enum)s_LAST_ID %(last)s
-#define %(enum)s_VALID_ID(id) \\
- ((id) >= %(enum)s_FIRST_ID && \\
- (id) <= %(enum)s_LAST_ID)
-""" % dict(enum=enum_name(cls), last=last))
- out.write("""
-/**
- * Function to check a wire ID
- * @param object_id The ID to check
- * @param base_object_id The inheritance parent, if applicable
- * @returns boolean: If base_object_id is an inheritance class, check if
- * object_id is valid as a subclass. Otherwise return 1.
- *
- * Note: Could check that object_id == base_object_id in the
- * second case.
- */
-static inline int
-of_wire_id_valid(int object_id, int base_object_id) {
- switch (base_object_id) {
- case OF_ACTION:
- return OF_ACTION_VALID_ID(object_id);
- case OF_OXM:
- return OF_OXM_VALID_ID(object_id);
- case OF_QUEUE_PROP:
- return OF_QUEUE_PROP_VALID_ID(object_id);
- case OF_TABLE_FEATURE_PROP:
- return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
- case OF_INSTRUCTION:
- return OF_INSTRUCTION_VALID_ID(object_id);
- default:
- break;
- }
- return 1;
-}
-""")
-
################################################################
#
# Internal Utility Functions
@@ -1055,7 +1000,8 @@
%(cls)s_header_t header; /* Generic instance */
""" % dict(cls=cls))
for subcls in sorted(subclasses):
- out.write(" %s_%s_t %s;\n" % (cls, subcls, subcls))
+ instance = loxi_utils.class_to_instance(subcls, cls)
+ out.write(" %s_%s_t %s;\n" % (cls, instance, instance))
out.write("};\n")
def gen_struct_typedefs(out):
@@ -1069,7 +1015,7 @@
out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
out.write("\n/* LOCI object typedefs */\n")
for cls in of_g.standard_class_order:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
continue
template = "typedef of_object_t %(cls)s_t;\n"
out.write(template % dict(cls=cls))
@@ -1109,7 +1055,7 @@
****************************************************************/
""")
for cls in of_g.standard_class_order:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("\n/* Unified accessor functions for %s */\n" % cls)
for m_name in of_g.ordered_members[cls]:
@@ -1629,7 +1575,7 @@
@param cls The class name for the function
@param out The file to which to write
"""
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
param = "obj_p"
else:
param = "obj"
@@ -1659,7 +1605,7 @@
""" % dict(cls=cls, param=param))
# Use an extra pointer to deal with inheritance classes
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
out.write("""\
%s_header_t *obj;
@@ -1862,7 +1808,7 @@
****************************************************************/
""")
for cls in of_g.standard_class_order:
-# if cls in type_maps.inheritance_map:
+# if type_maps.class_is_inheritance_root(cls):
# continue
out.write("""
/**
@@ -1921,7 +1867,7 @@
out.write("/* DOCUMENTATION ONLY */\n")
for cls in of_g.standard_class_order:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
pass # Check this
out.write("""
diff --git a/c_gen/c_dump_gen.py b/c_gen/c_dump_gen.py
index d4a016c..2f41c35 100644
--- a/c_gen/c_dump_gen.py
+++ b/c_gen/c_dump_gen.py
@@ -90,7 +90,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("""\
int %(cls)s_%(ver_name)s_dump(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
@@ -129,7 +129,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("""
int
@@ -234,7 +234,7 @@
comma = ","
if (not loxi_utils.class_in_version(cls, version) or
- cls in type_maps.inheritance_map):
+ type_maps.class_is_inheritance_root(cls)):
out.write(" unknown_dump%s\n" % comma);
else:
out.write(" %s_%s_dump%s\n" %
diff --git a/c_gen/c_show_gen.py b/c_gen/c_show_gen.py
index 9d84477..91eb595 100644
--- a/c_gen/c_show_gen.py
+++ b/c_gen/c_show_gen.py
@@ -91,7 +91,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("""\
int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
@@ -130,7 +130,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("""
int
@@ -233,7 +233,7 @@
comma = ","
if (not loxi_utils.class_in_version(cls, version) or
- cls in type_maps.inheritance_map):
+ type_maps.class_is_inheritance_root(cls)):
out.write(" unknown_show%s\n" % comma);
else:
out.write(" %s_%s_show%s\n" %
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 71615e6..41fe122 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -124,6 +124,13 @@
scalar_types = integer_types[:]
scalar_types.extend(string_types)
+# When embedding an object inside of another object we have to pick a single
+# subclass to use, unlike lists where we use all subclasses.
+embedded_subclasses = {
+ 'of_oxm_header_t': 'of_oxm_eth_type',
+ 'of_bsn_vport_header_t': 'of_bsn_vport_q_in_q',
+}
+
def ignore_member(cls, version, m_name, m_type):
"""
Filter out names or types that either don't have accessors
@@ -372,7 +379,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
out.write("""
extern int %(cls)s_%(v_name)s_populate(
@@ -507,7 +514,7 @@
*/
""" % v_name)
for cls in of_g.standard_class_order:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
continue
if version in of_g.unified[cls]:
message_scalar_test(out, version, cls)
@@ -520,7 +527,7 @@
for version in of_g.of_version_range:
v_name = loxi_utils.version_to_name(version)
for cls in of_g.standard_class_order:
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
continue
if version in of_g.unified[cls]:
test_name = "%s_%s" % (cls, v_name)
@@ -1301,8 +1308,9 @@
for m_type in member_types:
if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
- elif m_type == "of_bsn_vport_header_t":
- out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
+ elif m_type in embedded_subclasses:
+ subcls = embedded_subclasses[m_type]
+ out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
else:
out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
out.write("""
@@ -1313,7 +1321,7 @@
m_name = member["name"]
if loxi_utils.skip_member_name(m_name):
continue
- if m_type == "of_bsn_vport_header_t":
+ if m_type in embedded_subclasses:
continue
if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
out.write("""\
@@ -1363,8 +1371,8 @@
FREE(octets.data);
}
""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
- elif m_type == "of_bsn_vport_header_t": # test q_in_q
- sub_cls = "of_bsn_vport_q_in_q"
+ elif m_type in embedded_subclasses:
+ sub_cls = embedded_subclasses[m_type]
out.write("""\
%(var_name)s = %(sub_cls)s_new(%(v_name)s);
TEST_ASSERT(%(var_name)s != NULL);
@@ -1443,8 +1451,8 @@
value = of_octets_check(&%(var_name)s, value);
""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
v_name=loxi_utils.version_to_name(version)))
- elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
- sub_cls = "of_bsn_vport_q_in_q"
+ elif m_type in embedded_subclasses:
+ sub_cls = embedded_subclasses[m_type]
out.write("""
{ /* Use get/delete to access on check */
%(sub_cls)s_t *%(m_name)s_ptr;
@@ -1565,7 +1573,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
elif loxi_utils.class_is_list(cls):
gen_list_setup_check(out, cls, version)
@@ -1588,7 +1596,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
unified_accessor_test_case(out, cls, version)
@@ -1602,7 +1610,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
continue
test_name = "%s_%s" % (cls, v_name)
out.write(" RUN_TEST(%s);\n" % test_name)
@@ -1682,13 +1690,13 @@
""" % dict(cls=cls, ver_name=ver_name))
# For each subclass, check if this is an instance of that subclass
- version_classes = type_maps.inheritance_data[cls][version]
- for sub_cls in version_classes:
- sub_enum = (cls + "_" + sub_cls).upper()
+ sub_classes = type_maps.sub_class_map(cls, version)
+ for (_, sub_cls) in sub_classes:
+ sub_enum = sub_cls.upper()
out.write("""
if (src->header.object_id == %(sub_enum)s) {
- return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
- &src->%(sub_cls)s);
+ return (%(cls)s_t *)%(sub_cls)s_%(ver_name)s_dup(
+ (of_object_t *)src);
}
""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
@@ -1728,11 +1736,12 @@
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)))
- elif m_type == "of_bsn_vport_header_t": # test q_in_q
+ elif m_type in embedded_subclasses:
+ sub_cls = embedded_subclasses[m_type]
out.write("""
- of_bsn_vport_q_in_q_t src_%(v_name)s;
- of_bsn_vport_q_in_q_t *dst_%(v_name)s;
-""" % dict(v_name=var_name_map(m_type)))
+ %(sub_cls)s_t src_%(v_name)s;
+ %(sub_cls)s_t *dst_%(v_name)s;
+""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
else:
out.write("""
%(m_type)s src_%(v_name)s;
@@ -1760,8 +1769,8 @@
%(cls)s_%(m_name)s_get(src, &%(v_name)s);
%(cls)s_%(m_name)s_set(dst, &%(v_name)s);
""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
- elif m_type == "of_bsn_vport_header_t": # test q_in_q
- sub_cls = "of_bsn_vport_q_in_q"
+ elif m_type in embedded_subclasses:
+ sub_cls = embedded_subclasses[m_type]
out.write("""
%(cls)s_%(m_name)s_bind(
src, &src_%(v_name)s);
@@ -1814,7 +1823,7 @@
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:
+ if type_maps.class_is_inheritance_root(cls):
gen_dup_inheritance(out, cls, version)
elif loxi_utils.class_is_list(cls):
gen_dup_list(out, cls, version)
@@ -1836,7 +1845,7 @@
for version in of_g.of_version_range:
if not loxi_utils.class_in_version(cls, version):
continue
- hdr = "header." if cls in type_maps.inheritance_map else ""
+ hdr = "header." if type_maps.class_is_inheritance_root(cls) else ""
ver_name = loxi_utils.version_to_name(version)
out.write("""
@@ -1940,7 +1949,7 @@
for j, cls in enumerate(of_g.all_class_order):
if not loxi_utils.class_in_version(cls, version):
continue
- if cls in type_maps.inheritance_map:
+ if type_maps.class_is_inheritance_root(cls):
continue
if cls == "of_bsn_virtual_port_create_request": # test q_in_q
out.write("""
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 07b0ade..c1b00ad 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -207,69 +207,29 @@
if uclass and not uclass.virtual and uclass.has_type_members:
wire_type_set = '%s_push_wire_types' % uclass.name
+ root = uclass.inheritance_root()
+ if root and root.name != 'of_header':
+ wire_type_get = root.name + '_wire_object_id_get'
+
if uclass.is_message:
wire_length_get = 'of_object_message_wire_length_get'
wire_length_set = 'of_object_message_wire_length_set'
- elif uclass.is_action:
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_action_wire_object_id_get'
- elif uclass.is_instanceof('of_bsn_vport'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_bsn_vport_wire_object_id_get'
- elif uclass.is_action_id:
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_action_id_wire_object_id_get'
- elif uclass.is_instruction:
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_instruction_wire_object_id_get'
- elif uclass.is_instanceof('of_instruction_id'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_instruction_id_wire_object_id_get'
- elif uclass.is_instanceof('of_queue_prop'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_queue_prop_wire_object_id_get'
- elif uclass.is_instanceof('of_table_feature_prop'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_table_feature_prop_wire_object_id_get'
- elif uclass.is_instanceof('of_meter_band'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_meter_band_wire_object_id_get'
- elif uclass.is_instanceof('of_hello_elem'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_hello_elem_wire_object_id_get'
- elif uclass.is_instanceof('of_bsn_tlv'):
- wire_length_set = 'of_tlv16_wire_length_set'
- wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_get = 'of_bsn_tlv_wire_object_id_get'
elif uclass.is_oxm:
wire_length_get = 'of_oxm_wire_length_get'
- wire_type_get = 'of_oxm_wire_object_id_get'
elif uclass.name == "of_packet_queue":
+ # u16 len, but at offset 4
wire_length_get = 'of_packet_queue_wire_length_get'
wire_length_set = 'of_packet_queue_wire_length_set'
elif uclass.name == "of_meter_stats":
+ # u16 len, but at offset 4
wire_length_get = 'of_meter_stats_wire_length_get'
wire_length_set = 'of_meter_stats_wire_length_set'
- elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
- "of_flow_stats_entry", "of_bucket", "of_table_features",
- "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
- "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
- "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]:
- wire_length_get = "of_u16_len_wire_length_get"
- wire_length_set = "of_u16_len_wire_length_set"
- elif uclass.name == 'of_match_v3':
+ elif loxi_utils_legacy.class_is_tlv16(uclass.name):
wire_length_set = 'of_tlv16_wire_length_set'
wire_length_get = 'of_tlv16_wire_length_get'
- wire_type_set = 'of_match_v3_push_wire_types'
+ elif loxi_utils_legacy.class_is_u16_len(uclass.name):
+ wire_length_get = "of_u16_len_wire_length_get"
+ wire_length_set = "of_u16_len_wire_length_set"
class_metadata.append(ClassMetadata(
name=uclass.name,
@@ -278,74 +238,15 @@
wire_type_get=wire_type_get,
wire_type_set=wire_type_set))
- class_metadata.extend([
- ClassMetadata(
- name="of_action_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_action_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_action_id_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_action_id_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_bsn_vport_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_bsn_vport_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_instruction_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_instruction_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_instruction_id_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_instruction_id_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_queue_prop_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_queue_prop_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_table_feature_prop_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_table_feature_prop_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_meter_band_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_meter_band_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_hello_elem_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_hello_elem_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_bsn_tlv_header",
- wire_length_set='of_tlv16_wire_length_set',
- wire_length_get='of_tlv16_wire_length_get',
- wire_type_get='of_bsn_tlv_wire_object_id_get',
- wire_type_set='NULL'),
- ClassMetadata(
- name="of_oxm_header",
- wire_length_set='NULL',
- wire_length_get='of_oxm_wire_length_get',
- wire_type_get='of_oxm_wire_object_id_get',
- wire_type_set='NULL'),
- ])
+ # If this is the root of an inheritance hierachy, add metadata
+ # for the corresponding header class
+ if uclass.name in type_maps.inheritance_map:
+ class_metadata.append(ClassMetadata(
+ name=uclass.name + '_header',
+ wire_length_get=wire_length_get,
+ wire_length_set=wire_length_set,
+ wire_type_get=wire_type_get,
+ wire_type_set=wire_type_set))
for metadata in class_metadata:
class_metadata_dict[metadata.name] = metadata
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 4472ffa..0399638 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -37,6 +37,8 @@
import c_gen.of_g_legacy as of_g
import tenjin
from generic_utils import find, memoize
+import loxi_globals
+from loxi_ir import ir
def class_signature(members):
"""
@@ -99,40 +101,49 @@
"""
Return True if cls_name is an object which uses uint16 for type and length
"""
- if cls.find("of_action") == 0: # Includes of_action_id classes
- return True
- if cls.find("of_instruction") == 0:
- return True
- if cls.find("of_queue_prop") == 0:
- return True
- if cls.find("of_table_feature_prop") == 0:
- return True
- # *sigh*
- if cls.find("of_meter_band_stats") == 0: # NOT A TLV
+
+ ofclass = loxi_globals.unified.class_by_name(cls)
+ if not ofclass:
return False
- if cls.find("of_meter_band") == 0:
- return True
- if cls.find("of_hello_elem") == 0:
- return True
- if cls == "of_match_v3":
- return True
- if cls == "of_match_v4":
- return True
- if cls.find("of_bsn_tlv") == 0:
- return True
- if cls.find("of_bsn_vport") == 0:
- return True
- return False
+
+ if len(ofclass.members) < 2:
+ return False
+
+ m1 = ofclass.members[0]
+ m2 = ofclass.members[1]
+
+ if not (isinstance(m1, ir.OFTypeMember) or isinstance(m1, ir.OFDiscriminatorMember)):
+ return False
+
+ if not isinstance(m2, ir.OFLengthMember):
+ return False
+
+ if m1.oftype != "uint16_t" or m2.oftype != "uint16_t":
+ return False
+
+ return True
def class_is_u16_len(cls):
"""
Return True if cls_name is an object which uses initial uint16 length
"""
- return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
- "of_flow_stats_entry", "of_bucket", "of_table_features",
- "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
- "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
- "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]
+
+ ofclass = loxi_globals.unified.class_by_name(cls)
+ if not ofclass:
+ return False
+
+ if len(ofclass.members) < 1:
+ return False
+
+ m = ofclass.members[0]
+
+ if not isinstance(m, ir.OFLengthMember):
+ return False
+
+ if m.oftype != "uint16_t":
+ return False
+
+ return True
def class_is_list(cls):
"""
@@ -219,6 +230,10 @@
"""
return parent + "_" + instance
+def class_to_instance(cls, base_cls):
+ assert cls.startswith(base_cls + '_')
+ return cls[len(base_cls)+1:]
+
def class_is_var_len(cls, version):
# Match is special case. Only version 1.2 (wire version 3) is var
if cls == "of_match":
@@ -283,7 +298,7 @@
"""
Convert an integer version to the C macro name
"""
- return "OF_" + of_g.version_names[version]
+ return of_g.of_version_wire2name[version]
def gen_c_copy_license(out):
"""
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index b58ca08..2372b31 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -31,8 +31,7 @@
# @fixme This needs to be refactored and brought into the 21st century.
#
-import sys
-# @fixme Replace with argparse
+import loxi_globals
################################################################
#
@@ -286,25 +285,21 @@
# Indexed by (cls, version, member-name) and value is prev-member-name
special_offsets = {}
-## Define Python variables with integer wire version values
-VERSION_1_0 = 1
-VERSION_1_1 = 2
-VERSION_1_2 = 3
-VERSION_1_3 = 4
-
-version_names = {1:"VERSION_1_0", 2:"VERSION_1_1", 3:"VERSION_1_2",
- 4:"VERSION_1_3"}
-short_version_names = {1:"OF_1_0", 2:"OF_1_1", 3:"OF_1_2", 4:"OF_1_3"}
+# Map from wire version to OF_1_x
+short_version_names = {}
# The iteration object that gives the wire versions supported
-of_version_range = [VERSION_1_0, VERSION_1_1, VERSION_1_2, VERSION_1_3]
+of_version_range = []
-of_version_wire2name = {
- VERSION_1_0:"OF_VERSION_1_0",
- VERSION_1_1:"OF_VERSION_1_1",
- VERSION_1_2:"OF_VERSION_1_2",
- VERSION_1_3:"OF_VERSION_1_3"
- }
+# Map from wire version to OF_VERSION_1_x
+of_version_wire2name = {}
+
+for version in loxi_globals.OFVersions.all_supported:
+ v = version.version.replace('.', '_')
+ short_version_names[version.wire_version] = 'OF_' + v
+ of_version_range.append(version.wire_version)
+ of_version_wire2name[version.wire_version] = 'OF_VERSION_' + v
+ globals()['VERSION_' + v] = version.wire_version
################################################################
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 5647d81..596d79a 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -581,9 +581,6 @@
if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
of_object_id_t id;
loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
- if (!of_wire_id_valid(id, base_object_id)) {
- return OF_ERROR_PARSE;
- }
obj->object_id = id;
/* Call the init function for this object type; do not push to wire */
of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 6cbb3a5..3544d80 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -25,126 +25,12 @@
# EPL for the specific language governing permissions and limitations
# under the EPL.
-#
-# Miscellaneous type information
-#
-# Define the map between sub-class types and wire values. In each
-# case, an array indexed by wire version gives a hash from identifier
-# to wire value.
-#
-
-import c_gen.of_g_legacy as of_g
-import sys
from generic_utils import *
-import loxi_utils.loxi_utils as loxi_utils
import c_gen.loxi_utils_legacy as loxi_utils
import loxi_globals
-invalid_type = "invalid_type"
-
-################################################################
-#
-# Define type data for inheritance classes:
-# instructions, actions, queue properties and OXM
-#
-# Messages are not in this group; they're treated specially for now
-#
-# These are indexed by wire protocol number
-#
-################################################################
-
-instruction_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict()
- }
-
-instruction_id_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict()
- }
-
-action_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-action_id_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-queue_prop_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict()
- }
-
-bsn_vport_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-oxm_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-hello_elem_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-table_feature_prop_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-meter_band_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-bsn_tlv_types = {
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(),
- }
-
-# All inheritance data for non-messages
-inheritance_data = dict(
- of_instruction = instruction_types,
- of_instruction_id = instruction_id_types,
- of_action = action_types,
- of_action_id = action_id_types,
- of_oxm = oxm_types,
- of_queue_prop = queue_prop_types,
- of_hello_elem = hello_elem_types,
- of_table_feature_prop = table_feature_prop_types,
- of_meter_band = meter_band_types,
- # BSN specific inheritance extensions
- of_bsn_vport = bsn_vport_types,
- of_bsn_tlv = bsn_tlv_types,
- )
+# map from inheritance root class name to set of subclass names
+inheritance_map = {}
def class_is_virtual(cls):
"""
@@ -156,301 +42,20 @@
return True
return loxi_globals.unified.class_by_name(cls).virtual
-################################################################
-#
-# These are message types
-#
-################################################################
-
-# The hardcoded message types are for inheritance parents
-message_types = {
- # version 1.0
- of_g.VERSION_1_0:dict(
- error_msg = 1,
- experimenter = 4,
- flow_mod = 14,
- stats_request = 16,
- stats_reply = 17,
- ),
-
- # version 1.1
- of_g.VERSION_1_1:dict(
- error_msg = 1,
- experimenter = 4,
- flow_mod = 14,
- group_mod = 15,
- stats_request = 18,
- stats_reply = 19,
- ),
-
- # version 1.2
- of_g.VERSION_1_2:dict(
- error_msg = 1,
- experimenter = 4,
- flow_mod = 14,
- group_mod = 15,
- stats_request = 18,
- stats_reply = 19,
- ),
-
- # version 1.3
- of_g.VERSION_1_3:dict(
- error_msg = 1,
- experimenter = 4,
- flow_mod = 14,
- group_mod = 15,
- stats_request = 18, # FIXME Multipart
- stats_reply = 19,
- )
- }
-
-################################################################
-#
-# These are other objects that have a notion of type but are
-# not (yet) promoted to objects with inheritance
-#
-################################################################
-
-stats_types = {
- # version 1.0
- of_g.VERSION_1_0:dict(
- desc = 0,
- flow = 1,
- aggregate = 2,
- table = 3,
- port = 4,
- queue = 5,
- experimenter = 0xffff
- ),
-
- # version 1.1
- of_g.VERSION_1_1:dict(
- desc = 0,
- flow = 1,
- aggregate = 2,
- table = 3,
- port = 4,
- queue = 5,
- group = 6,
- group_desc = 7,
- experimenter = 0xffff
- ),
-
- # version 1.2
- of_g.VERSION_1_2:dict(
- desc = 0,
- flow = 1,
- aggregate = 2,
- table = 3,
- port = 4,
- queue = 5,
- group = 6,
- group_desc = 7,
- group_features = 8,
- experimenter = 0xffff
- ),
-
- # version 1.3
- of_g.VERSION_1_3:dict(
- desc = 0,
- flow = 1,
- aggregate = 2,
- table = 3,
- port = 4,
- queue = 5,
- group = 6,
- group_desc = 7,
- group_features = 8,
- meter = 9,
- meter_config = 10,
- meter_features = 11,
- table_features = 12,
- port_desc = 13,
- experimenter = 0xffff,
- bsn_lacp = 0xffff,
- bsn_switch_pipeline = 0xffff,
- bsn_port_counter = 0xffff,
- bsn_vlan_counter = 0xffff
- )
- }
-
-common_flow_mod_types = dict(
- add = 0,
- modify = 1,
- modify_strict = 2,
- delete = 3,
- delete_strict = 4
- )
-
-flow_mod_types = {
- # version 1.0
- of_g.VERSION_1_0:common_flow_mod_types,
- of_g.VERSION_1_1:common_flow_mod_types,
- of_g.VERSION_1_2:common_flow_mod_types,
- of_g.VERSION_1_3:common_flow_mod_types
- }
-
-# These do not translate to objects (yet)
-error_types = {
- # version 1.0
- of_g.VERSION_1_0:dict(
- hello_failed = 0,
- bad_request = 1,
- bad_action = 2,
- flow_mod_failed = 3,
- port_mod_failed = 4,
- queue_op_failed = 5
- ),
-
- # version 1.1
- of_g.VERSION_1_1:dict(
- hello_failed = 0,
- bad_request = 1,
- bad_action = 2,
- bad_instruction = 3,
- bad_match = 4,
- flow_mod_failed = 5,
- group_mod_failed = 6,
- port_mod_failed = 7,
- table_mod_failed = 8,
- queue_op_failed = 9,
- switch_config_failed = 10
- ),
-
- # version 1.2
- of_g.VERSION_1_2:dict(
- hello_failed = 0,
- bad_request = 1,
- bad_action = 2,
- bad_instruction = 3,
- bad_match = 4,
- flow_mod_failed = 5,
- group_mod_failed = 6,
- port_mod_failed = 7,
- table_mod_failed = 8,
- queue_op_failed = 9,
- switch_config_failed = 10,
- role_request_failed = 11,
- experimenter = 0xffff
- ),
-
- # version 1.3
- of_g.VERSION_1_3:dict(
- hello_failed = 0,
- bad_request = 1,
- bad_action = 2,
- bad_instruction = 3,
- bad_match = 4,
- flow_mod_failed = 5,
- group_mod_failed = 6,
- port_mod_failed = 7,
- table_mod_failed = 8,
- queue_op_failed = 9,
- switch_config_failed = 10,
- role_request_failed = 11,
- meter_mod_failed = 12,
- table_features_failed= 13,
- experimenter = 0xffff
- )
- }
-
-group_mod_types = {
- # version 1.0
- of_g.VERSION_1_0:dict(),
-
- # version 1.1
- of_g.VERSION_1_1:dict(
- add = 0,
- modify = 1,
- delete = 2
- ),
-
- # version 1.2
- of_g.VERSION_1_2:dict(
- add = 0,
- modify = 1,
- delete = 2
- ),
-
- # version 1.3
- of_g.VERSION_1_3:dict(
- add = 0,
- modify = 1,
- delete = 2
- )
- }
-
-################################################################
-#
-# type_val is the primary data structure that maps an
-# (class_name, version) pair to the wire data type value
-#
-################################################################
-
-type_val = dict()
-inheritance_map = dict()
+def class_is_inheritance_root(cls):
+ return cls in inheritance_map
def generate_maps():
- for parent, versioned in inheritance_data.items():
- inheritance_map[parent] = set()
- for ver, subclasses in versioned.items():
- for subcls in subclasses:
- inheritance_map[parent].add(subcls)
+ for version, protocol in loxi_globals.ir.items():
+ wire_version = version.wire_version
+ for ofclass in protocol.classes:
+ root = ofclass.inheritance_root()
+ if not root or root == ofclass or root.name == "of_header":
+ continue
- for version, classes in message_types.items():
- for cls in classes:
- name = "of_" + cls
- type_val[(name, version)] = classes[cls]
-
- for parent, versioned in inheritance_data.items():
- for version, subclasses in versioned.items():
- for subcls, value in subclasses.items():
- name = parent + "_" + subcls
- type_val[(name, version)] = value
-
- # Special case OF-1.2 match type
- type_val[("of_match_v3", of_g.VERSION_1_2)] = 1
- type_val[("of_match_v3", of_g.VERSION_1_3)] = 1
-
-# Utility function
-def dict_to_array(d, m_val, def_val=-1):
- """
- Given a dictionary, d, with each value a small integer,
- produce an array indexed by the integer whose value is the key.
- @param d The dictionary
- @param m_val Ignore values greater than m_val
- @param def_val The default value (for indices not in range of d)
- """
-
- # Get the max value in range for hash
- max_val = 0
- for key in d:
- if (d[key] > max_val) and (d[key] < m_val):
- max_val = d[key]
- ar = []
- for x in range(0, max_val + 1):
- ar.append(def_val)
- for key in d:
- if (d[key] < m_val):
- ar[d[key]] = key
- return ar
-
-def type_array_len(version_indexed, max_val):
- """
- Given versioned information about a type, calculate how long
- the unified array should be.
-
- @param version_indexed A dict indexed by version. Each value is a
- dict indexed by a name and whose value is an integer
- @param max_val Ignore values greater than this for length calcs
- """
- # First, find the max length of all arrays
- arr_len = 0
- for version, val_dict in version_indexed.items():
- ar = dict_to_array(val_dict, max_val, invalid_type)
- if arr_len < len(ar):
- arr_len = len(ar)
- return arr_len
+ if root.name not in inheritance_map:
+ inheritance_map[root.name] = set()
+ inheritance_map[root.name].add(ofclass.name)
def sub_class_map(base_type, version):
"""
@@ -461,99 +66,10 @@
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)
+ for subcls in inheritance_map[base_type]:
if not loxi_utils.class_in_version(subcls, version):
continue
+ instance = loxi_utils.class_to_instance(subcls, base_type)
rv.append((instance, subcls))
return rv
-
-################################################################
-#
-# Extension related data and functions
-#
-################################################################
-
-# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
-# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
-extension_message_subtype = {
- # version 1.0
- of_g.VERSION_1_0:dict( # Version 1.0 extensions
- bsn = { # BSN extensions; indexed by class name, value is subtype
- },
- nicira = { # Nicira extensions, value is subtype
- },
- ),
- of_g.VERSION_1_1:dict( # Version 1.0 extensions
- bsn = { # BSN extensions; indexed by class name, value is subtype
- },
- ),
- of_g.VERSION_1_2:dict( # Version 1.0 extensions
- bsn = { # BSN extensions; indexed by class name, value is subtype
- },
- ),
- of_g.VERSION_1_3:dict( # Version 1.0 extensions
- bsn = { # BSN extensions; indexed by class name, value is subtype
- },
- ),
-}
-
-# Set to empty dict if no extension actions defined
-# Per OF Version, per experimenter, map actions to subtype
-extension_action_subtype = {
- # version 1.0
- of_g.VERSION_1_0:dict( # Version 1.0 extensions
- bsn = { # of_action_bsn_
- },
- nicira = { # of_action_nicira_
- }
- ),
- of_g.VERSION_1_1:dict( # Version 1.0 extensions
- bsn = { # of_action_bsn_
- },
- nicira = { # of_action_nicira_
- }
- ),
- of_g.VERSION_1_2:dict( # Version 1.0 extensions
- bsn = { # of_action_bsn_
- },
- nicira = { # of_action_nicira_
- }
- ),
- of_g.VERSION_1_3:dict( # Version 1.0 extensions
- bsn = { # of_action_bsn_
- },
- nicira = { # of_action_nicira_
- }
- ),
-}
-
-# Set to empty dict if no extension actions defined
-# Per OF Version, per experimenter, map actions to subtype
-extension_action_id_subtype = {
- # version 1.0
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict( # Version 1.3 extensions
- bsn = { # of_action_bsn_
- },
- nicira = { # of_action_nicira_
- }
- ),
-}
-
-# Set to empty dict if no extension instructions defined
-extension_instruction_subtype = {
- # version 1.0
- of_g.VERSION_1_0:dict(),
- of_g.VERSION_1_1:dict(),
- of_g.VERSION_1_2:dict(),
- of_g.VERSION_1_3:dict(
- bsn = { # of_instruction_bsn_
- },
- nicira = { # of_instruction_nicira_
- }
- ),
-}
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index 0e95473..7b9a0b6 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -145,6 +145,15 @@
def is_subclassof(self, super_class_name):
return self.name != super_class_name and self.is_instanceof(super_class_name)
+ def inheritance_root(self):
+ if not self.superclass:
+ if self.virtual:
+ return self
+ else:
+ return None
+ else:
+ return self.superclass.inheritance_root()
+
@property
def is_message(self):
return self.is_instanceof("of_header")