blob: f052950078cc4acd5944c8258d68fb50e52cca5c [file] [log] [blame]
Rich Lanebdd8e292013-12-06 17:37:39 -08001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29Code generation
30
31These functions extract data from the IR and render templates with it.
32"""
33
34from collections import namedtuple
35from itertools import groupby
Rich Lanedef2e512013-12-15 15:54:02 -080036from StringIO import StringIO
Rich Lanebdd8e292013-12-06 17:37:39 -080037import template_utils
Rich Lanef51062b2014-02-24 23:08:26 -080038from generic_utils import chunks
Rich Lanebdd8e292013-12-06 17:37:39 -080039import loxi_globals
40import loxi_ir.ir as ir
41import util
Rich Lanece2e4642013-12-15 12:05:45 -080042import c_code_gen
Rich Lane8c4c23f2013-12-15 13:22:13 -080043import c_gen.of_g_legacy as of_g
Rich Lanecce961d2013-12-15 14:20:42 -080044import c_gen.type_maps as type_maps
Rich Lanec0e20ff2013-12-15 23:40:31 -080045import c_gen.c_type_maps as c_type_maps
Rich Lane2cc2b862014-06-13 14:50:17 -070046import loxi_utils.loxi_utils as loxi_utils
47import c_gen.loxi_utils_legacy as loxi_utils_legacy
Rich Lanebdd8e292013-12-06 17:37:39 -080048
Rich Lanef51062b2014-02-24 23:08:26 -080049CLASS_CHUNK_SIZE = 32
50
Rich Lane22811f52013-12-15 15:28:03 -080051PushWireTypesData = namedtuple('PushWireTypesData',
Rich Lanebdd8e292013-12-06 17:37:39 -080052 ['class_name', 'versioned_type_members'])
53PushWireTypesMember = namedtuple('PushWireTypesMember',
54 ['name', 'offset', 'length', 'value'])
55
Rich Lane22811f52013-12-15 15:28:03 -080056def push_wire_types_data(uclass):
57 if uclass.virtual or not uclass.has_type_members:
58 return None
Rich Lanebdd8e292013-12-06 17:37:39 -080059
Rich Lane22811f52013-12-15 15:28:03 -080060 # Generate a dict of version -> list of PushWireTypesMember
61 type_members_by_version = {}
62 for version, ofclass in sorted(uclass.version_classes.items()):
63 pwtms = []
64 for m in ofclass.members:
65 if isinstance(m, ir.OFTypeMember):
66 if m.name == "version" and m.value == version.wire_version:
67 # Special case for version
68 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
69 else:
Rich Laned0c58712013-12-18 10:02:47 -080070 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
Rich Lane22811f52013-12-15 15:28:03 -080071 type_members_by_version[version] = pwtms
Rich Lanebdd8e292013-12-06 17:37:39 -080072
Rich Lane22811f52013-12-15 15:28:03 -080073 # Merge versions with identical type members
74 all_versions = sorted(type_members_by_version.keys())
75 versioned_type_members = []
76 for pwtms, versions in groupby(all_versions, type_members_by_version.get):
77 versioned_type_members.append((pwtms, list(versions)))
Rich Lanebdd8e292013-12-06 17:37:39 -080078
Rich Lane22811f52013-12-15 15:28:03 -080079 return PushWireTypesData(
80 class_name=uclass.name,
81 versioned_type_members=versioned_type_members)
Rich Lanece2e4642013-12-15 12:05:45 -080082
Rich Laneb9fab4b2014-03-04 18:44:08 -080083ParseWireTypesData = namedtuple('ParseWireTypesData',
84 ['class_name', 'versioned'])
85ParseWireTypesVersion = namedtuple('ParseWireTypesVersion',
86 ['discriminator', 'subclasses'])
87ParseWireTypesSubclass = namedtuple('ParseWireTypesSubclass',
88 ['class_name', 'value', 'virtual'])
89
90def parse_wire_types_data(uclass):
91 if not uclass.virtual:
92 return None
93
Rich Laneb9fab4b2014-03-04 18:44:08 -080094 # Generate a dict of version -> ParseWireTypesVersion
95 versioned = {}
96 for version, ofclass in sorted(uclass.version_classes.items()):
Rich Lanea4b68302014-03-12 15:17:58 -070097 discriminator = ofclass.discriminator
Rich Laneb9fab4b2014-03-04 18:44:08 -080098 subclasses = [ParseWireTypesSubclass(class_name=subclass.name,
99 value=subclass.member_by_name(discriminator.name).value,
100 virtual=subclass.virtual)
101 for subclass in ofclass.protocol.classes if subclass.superclass and subclass.superclass.name == ofclass.name]
102
103 subclasses.sort(key=lambda x: x.value)
104 versioned[version] = ParseWireTypesVersion(discriminator=discriminator,
105 subclasses=subclasses)
106
107 return ParseWireTypesData(class_name=uclass.name,
108 versioned=sorted(versioned.items()))
109
Rich Lanef51062b2014-02-24 23:08:26 -0800110# Output multiple LOCI classes into each C file. This reduces the overhead of
111# parsing header files, which takes longer than compiling the actual code
112# for many classes. It also reduces the compiled code size.
Rich Lanece2e4642013-12-15 12:05:45 -0800113def generate_classes(install_dir):
Rich Lanef51062b2014-02-24 23:08:26 -0800114 for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
115 with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
116 for uclass in chunk:
117 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800118 push_wire_types_data=push_wire_types_data(uclass),
119 parse_wire_types_data=parse_wire_types_data(uclass))
Rich Lanef51062b2014-02-24 23:08:26 -0800120 # Append legacy generated code
121 c_code_gen.gen_new_function_definitions(out, uclass.name)
122 c_code_gen.gen_accessor_definitions(out, uclass.name)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800123
Rich Lanedef2e512013-12-15 15:54:02 -0800124def generate_classes_header(install_dir):
125 # Collect legacy code
126 tmp = StringIO()
127 c_code_gen.gen_struct_typedefs(tmp)
128 c_code_gen.gen_new_function_declarations(tmp)
129 c_code_gen.gen_accessor_declarations(tmp)
Rich Lanedef2e512013-12-15 15:54:02 -0800130
131 with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
132 util.render_template(out, "loci_classes.h",
133 legacy_code=tmp.getvalue())
134
Rich Lane8c4c23f2013-12-15 13:22:13 -0800135def generate_lists(install_dir):
Rich Lane2cc2b862014-06-13 14:50:17 -0700136 # Collect all the lists in use
137 list_oftypes = set()
138 for uclass in loxi_globals.unified.classes:
Rich Lanedeb96752014-06-25 22:27:51 -0700139 for ofclass in uclass.version_classes.values():
Rich Lane2cc2b862014-06-13 14:50:17 -0700140 for m in ofclass.members:
Rich Lanedeb96752014-06-25 22:27:51 -0700141 if isinstance(m, ir.OFDataMember) and \
142 loxi_utils.oftype_is_list(m.oftype):
143 list_oftypes.add(m.oftype)
Rich Lane2cc2b862014-06-13 14:50:17 -0700144
145 for oftype in sorted(list(list_oftypes)):
146 cls, e_cls = loxi_utils_legacy.list_name_extract(oftype)
147 e_cls = e_cls[:-2]
Rich Lane83f958d2014-06-13 15:01:40 -0700148 e_uclass = loxi_globals.unified.class_by_name(e_cls)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800149 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane83f958d2014-06-13 15:01:40 -0700150 util.render_template(out, "list.c", cls=cls, e_cls=e_cls, e_uclass=e_uclass,
Rich Lanebbf5e1d2014-06-13 15:34:21 -0700151 wire_length_get=class_metadata_dict[e_cls].wire_length_get)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800152 # Append legacy generated code
Rich Laneb604e332013-12-15 13:23:51 -0800153 c_code_gen.gen_new_function_definitions(out, cls)
Rich Lane8a822732013-12-15 14:06:32 -0800154
155def generate_strings(install_dir):
156 object_id_strs = []
157 object_id_strs.append("of_object")
158 object_id_strs.extend(of_g.ordered_messages)
159 object_id_strs.extend(of_g.ordered_non_messages)
160 object_id_strs.extend(of_g.ordered_list_objects)
161 object_id_strs.extend(of_g.ordered_pseudo_objects)
162 object_id_strs.append("of_unknown_object")
163
164 with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
165 util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
Rich Lanecce961d2013-12-15 14:20:42 -0800166
167def generate_init_map(install_dir):
168 with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
169 util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800170
171def generate_type_maps(install_dir):
172 # Collect legacy code
173 tmp = StringIO()
Rich Lanec0e20ff2013-12-15 23:40:31 -0800174 c_type_maps.gen_length_array(tmp)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800175
176 with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
177 util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
Rich Lanedc46fe22014-04-03 15:10:38 -0700178
179ClassMetadata = namedtuple('ClassMetadata',
180 ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
181
Rich Lane08c9f3a2014-06-13 11:24:37 -0700182class_metadata = []
183class_metadata_dict = {}
184
Rich Lane127860e2014-10-14 11:03:49 -0700185# These classes have handwritten C code to get/set their length fields
186# See templates/of_type_maps.c
187special_length_classes = set([
188 'of_packet_queue', 'of_meter_stats', 'of_port_desc',
189 'of_port_stats_entry', 'of_queue_stats_entry',
Rich Lane7329b542014-10-17 18:30:13 -0700190 'of_queue_desc',
Rich Lane127860e2014-10-14 11:03:49 -0700191])
192
Rich Lane08c9f3a2014-06-13 11:24:37 -0700193def build_class_metadata():
194 for uclass in loxi_globals.unified.classes:
195 wire_length_get = 'NULL'
196 wire_length_set = 'NULL'
197 wire_type_get = 'NULL'
198 wire_type_set = 'NULL'
199
200 if uclass and not uclass.virtual and uclass.has_type_members:
201 wire_type_set = '%s_push_wire_types' % uclass.name
202
Rich Lane068847f2014-10-13 16:26:33 -0700203 root = uclass.inheritance_root()
204 if root and root.name != 'of_header':
205 wire_type_get = root.name + '_wire_object_id_get'
206
Rich Lane08c9f3a2014-06-13 11:24:37 -0700207 if uclass.is_message:
208 wire_length_get = 'of_object_message_wire_length_get'
209 wire_length_set = 'of_object_message_wire_length_set'
Rich Lane08c9f3a2014-06-13 11:24:37 -0700210 elif uclass.is_oxm:
211 wire_length_get = 'of_oxm_wire_length_get'
Rich Lane127860e2014-10-14 11:03:49 -0700212 elif uclass.name in special_length_classes:
213 wire_length_get = '%s_wire_length_get' % uclass.name
214 wire_length_set = '%s_wire_length_set' % uclass.name
Rich Lane068847f2014-10-13 16:26:33 -0700215 elif loxi_utils_legacy.class_is_tlv16(uclass.name):
Rich Lane08c9f3a2014-06-13 11:24:37 -0700216 wire_length_set = 'of_tlv16_wire_length_set'
217 wire_length_get = 'of_tlv16_wire_length_get'
Rich Lane068847f2014-10-13 16:26:33 -0700218 elif loxi_utils_legacy.class_is_u16_len(uclass.name):
219 wire_length_get = "of_u16_len_wire_length_get"
220 wire_length_set = "of_u16_len_wire_length_set"
Rich Lane08c9f3a2014-06-13 11:24:37 -0700221
222 class_metadata.append(ClassMetadata(
223 name=uclass.name,
224 wire_length_get=wire_length_get,
225 wire_length_set=wire_length_set,
226 wire_type_get=wire_type_get,
227 wire_type_set=wire_type_set))
228
Rich Lane08c9f3a2014-06-13 11:24:37 -0700229 for metadata in class_metadata:
230 class_metadata_dict[metadata.name] = metadata
231
Rich Lanedc46fe22014-04-03 15:10:38 -0700232def generate_class_metadata(install_dir):
233 with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
234 util.render_template(out, "loci_class_metadata.h")
235
236 with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
Rich Lanedc46fe22014-04-03 15:10:38 -0700237 util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)