loci: replace calculate_offsets_and_lengths with code using the IR
This function also searched for lists and special offsets. I moved this logic
to analyze_input.
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 8a7317a..ff2dfe8 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -119,140 +119,6 @@
if not m_name in of_g.ordered_members[cls]:
of_g.ordered_members[cls].append(m_name)
-def update_offset(cls, wire_version, name, offset, m_type):
- """
- Update (and return) the offset based on type.
- @param cls The parent class
- @param wire_version The wire version being processed
- @param name The name of the data member
- @param offset The current offset
- @param m_type The type declaration being processed
- @returns A pair (next_offset, len_update) next_offset is the new offset
- of the next object or -1 if this is a var-length object. len_update
- is the increment that should be added to the length. Note that (for
- of_match_v3) it is variable length, but it adds 8 bytes to the fixed
- length of the object
- If offset is already -1, do not update
- Otherwise map to base type and count and update (if possible)
- """
- if offset < 0: # Don't update offset once set to -1
- return offset, 0
-
- count, base_type = loxi_utils.type_dec_to_count_base(m_type)
-
- len_update = 0
- if base_type in of_g.of_mixed_types:
- base_type = of_g.of_mixed_types[base_type][wire_version]
-
- base_class = base_type[:-2]
- if (base_class, wire_version) in of_g.is_fixed_length:
- bytes = of_g.base_length[(base_class, wire_version)]
- else:
- if base_type == "of_match_v3_t":
- # This is a special case: it has non-zero min length
- # but is variable length
- bytes = -1
- len_update = 8
- elif base_type == "of_oxm_header_t":
- # This is a special case: it has non-zero min length
- # but is variable length
- bytes = -1
- len_update = 4
- elif base_type == "of_bsn_vport_header_t":
- # This is a special case: it has non-zero min length
- # but is variable length
- bytes = -1
- len_update = 4
- elif base_type == "of_port_desc_t":
- # This is a special case: it has non-zero min length
- # but is variable length
- bytes = -1
- len_update = of_g.base_length[(base_class, wire_version)]
- elif base_type in of_g.of_base_types:
- bytes = of_g.of_base_types[base_type]["bytes"]
- else:
- print "UNKNOWN TYPE for %s %s: %s" % (cls, name, base_type)
- log("UNKNOWN TYPE for %s %s: %s" % (cls, name, base_type))
- bytes = -1
-
- # If bytes
- if bytes > 0:
- len_update = count * bytes
-
- if bytes == -1:
- return -1, len_update
-
- return offset + (count * bytes), len_update
-
-def calculate_offsets_and_lengths(ordered_classes, classes, wire_version):
- """
- Generate the offsets for fixed offset class members
- Also calculate the class_sizes when possible.
-
- @param classes The classes to process
- @param wire_version The wire version for this set of classes
-
- Updates global variables
- """
-
- lists = set()
-
- # Generate offsets
- for cls in ordered_classes:
- fixed_offset = 0 # The last "good" offset seen
- offset = 0
- last_offset = 0
- last_name = "-"
- for member in classes[cls]:
- m_type = member["m_type"]
- name = member["name"]
- if last_offset == -1:
- if name == "pad":
- log("Skipping pad for special offset for %s" % cls)
- else:
- log("SPECIAL OFS: Member %s (prev %s), class %s ver %d" %
- (name, last_name, cls, wire_version))
- if (((cls, name) in of_g.special_offsets) and
- (of_g.special_offsets[(cls, name)] != last_name)):
- debug("ERROR: special offset prev name changed")
- debug(" cls %s. name %s. version %d. was %s. now %s" %
- cls, name, wire_version,
- of_g.special_offsets[(cls, name)], last_name)
- sys.exit(1)
- of_g.special_offsets[(cls, name)] = last_name
-
- member["offset"] = offset
- if m_type.find("list(") == 0:
- (list_name, base_type) = loxi_utils.list_name_extract(m_type)
- lists.add(list_name)
- member["m_type"] = list_name + "_t"
- offset = -1
- elif m_type.find("struct") == 0:
- debug("ERROR found struct: %s.%s " % (cls, name))
- sys.exit(1)
- elif m_type == "octets":
- log("offset gen skipping octets: %s.%s " % (cls, name))
- offset = -1
- else:
- offset, len_update = update_offset(cls, wire_version, name,
- offset, m_type)
- if offset != -1:
- fixed_offset = offset
- else:
- fixed_offset += len_update
- log("offset is -1 for %s.%s version %d " %
- (cls, name, wire_version))
- last_offset = offset
- last_name = name
- of_g.base_length[(cls, wire_version)] = fixed_offset
- if (offset != -1):
- of_g.is_fixed_length.add((cls, wire_version))
-
- for list_type in lists:
- classes[list_type] = []
- of_g.ordered_classes[wire_version].append(list_type)
- of_g.base_length[(list_type, wire_version)] = 0
-
def order_and_assign_object_ids():
"""
Order all classes and assign object ids to all classes.
@@ -334,11 +200,7 @@
pad_count = 0
for m in ofclass.members:
if type(m) == OFPadMember:
- m_name = 'pad%d' % pad_count
- if m_name == 'pad0': m_name = 'pad'
- legacy_members.append(dict(m_type='uint8_t[%d]' % m.length,
- name=m_name))
- pad_count += 1
+ continue
else:
# HACK the C backend does not yet support of_oxm_t
if m.oftype == 'of_oxm_t':
@@ -346,15 +208,28 @@
# HACK the C backend does not yet support of_bsn_vport_t
elif m.oftype == 'of_bsn_vport_t':
m_type = 'of_bsn_vport_header_t'
+ elif m.oftype.find("list(") == 0:
+ (list_name, base_type) = loxi_utils.list_name_extract(m.oftype)
+ m_type = list_name + "_t"
else:
enum = find(lambda e: e.name == m.oftype, protocol.enums)
if enum and "wire_type" in enum.params:
m_type = enum.params["wire_type"]
else:
m_type = m.oftype
- legacy_members.append(dict(m_type=m_type, name=m.name))
+
+ if m.offset is None:
+ m_offset = -1
+ else:
+ m_offset = m.offset
+
+ legacy_members.append(dict(m_type=m_type, name=m.name, offset=m_offset))
versions[version_name]['classes'][ofclass.name] = legacy_members
+ of_g.base_length[(ofclass.name, version.wire_version)] = ofclass.base_length
+ if ofclass.is_fixed_length:
+ of_g.is_fixed_length.add((ofclass.name, version.wire_version))
+
for enum in protocol.enums:
for entry in enum.entries:
identifiers.add_identifier(
@@ -382,13 +257,42 @@
new_cls = cls + '_header'
of_g.ordered_classes[wire_version].append(new_cls)
classes[new_cls] = classes[cls]
+ of_g.base_length[(new_cls, wire_version)] = of_g.base_length[(cls, wire_version)]
+ if (cls, wire_version) in of_g.is_fixed_length:
+ of_g.is_fixed_length.add((cls, wire_version))
- for wire_version in of_g.wire_ver_map.keys():
- version_name = of_g.of_version_wire2name[wire_version]
- calculate_offsets_and_lengths(
- of_g.ordered_classes[wire_version],
- versions[version_name]['classes'],
- wire_version)
+ # Create lists
+ for version, protocol in loxi_globals.ir.items():
+ lists = set()
+ classes = versions[of_g.of_version_wire2name[version.wire_version]]['classes']
+
+ for ofclass in protocol.classes:
+ for m in ofclass.members:
+ if isinstance(m, OFDataMember) and m.oftype.find("list(") == 0:
+ (list_name, base_type) = loxi_utils.list_name_extract(m.oftype)
+ lists.add(list_name)
+
+ for list_type in lists:
+ classes[list_type] = []
+ of_g.ordered_classes[version.wire_version].append(list_type)
+ of_g.base_length[(list_type, version.wire_version)] = 0
+
+ # Find special offsets
+ # These are defined as members (except padding) that don't have a fixed
+ # offset. The special_offsets map stores the name of the previous member.
+ for version, protocol in loxi_globals.ir.items():
+ for ofclass in protocol.classes:
+ prev_member = None
+ for m in ofclass.members:
+ if isinstance(m, OFPadMember):
+ continue
+ if m.offset == None:
+ old = of_g.special_offsets.get((ofclass.name, m.name))
+ if old and old != prev_member.name:
+ raise Exception("Error: special offset changed: version=%s cls=%s member=%s old=%s new=%s" %
+ (version, ofclass.name, m.name, old, prev_member.name))
+ of_g.special_offsets[(ofclass.name, m.name)] = prev_member.name
+ prev_member = m
def unify_input():
"""