blob: e2646e4fd4fddc761fd5dc93e803c875f1eb1a21 [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 Lane99d9a8d2014-06-13 14:05:10 -070046import c_gen.loxi_utils_legacy as loxi_utils
Rich Lanebdd8e292013-12-06 17:37:39 -080047
Rich Lanef51062b2014-02-24 23:08:26 -080048CLASS_CHUNK_SIZE = 32
49
Rich Lane22811f52013-12-15 15:28:03 -080050PushWireTypesData = namedtuple('PushWireTypesData',
Rich Lanebdd8e292013-12-06 17:37:39 -080051 ['class_name', 'versioned_type_members'])
52PushWireTypesMember = namedtuple('PushWireTypesMember',
53 ['name', 'offset', 'length', 'value'])
54
Rich Lane22811f52013-12-15 15:28:03 -080055def push_wire_types_data(uclass):
56 if uclass.virtual or not uclass.has_type_members:
57 return None
Rich Lanebdd8e292013-12-06 17:37:39 -080058
Rich Lane22811f52013-12-15 15:28:03 -080059 # Generate a dict of version -> list of PushWireTypesMember
60 type_members_by_version = {}
61 for version, ofclass in sorted(uclass.version_classes.items()):
62 pwtms = []
63 for m in ofclass.members:
64 if isinstance(m, ir.OFTypeMember):
65 if m.name == "version" and m.value == version.wire_version:
66 # Special case for version
67 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
68 else:
Rich Laned0c58712013-12-18 10:02:47 -080069 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
Rich Lane22811f52013-12-15 15:28:03 -080070 type_members_by_version[version] = pwtms
Rich Lanebdd8e292013-12-06 17:37:39 -080071
Rich Lane22811f52013-12-15 15:28:03 -080072 # Merge versions with identical type members
73 all_versions = sorted(type_members_by_version.keys())
74 versioned_type_members = []
75 for pwtms, versions in groupby(all_versions, type_members_by_version.get):
76 versioned_type_members.append((pwtms, list(versions)))
Rich Lanebdd8e292013-12-06 17:37:39 -080077
Rich Lane22811f52013-12-15 15:28:03 -080078 return PushWireTypesData(
79 class_name=uclass.name,
80 versioned_type_members=versioned_type_members)
Rich Lanece2e4642013-12-15 12:05:45 -080081
Rich Laneb9fab4b2014-03-04 18:44:08 -080082ParseWireTypesData = namedtuple('ParseWireTypesData',
83 ['class_name', 'versioned'])
84ParseWireTypesVersion = namedtuple('ParseWireTypesVersion',
85 ['discriminator', 'subclasses'])
86ParseWireTypesSubclass = namedtuple('ParseWireTypesSubclass',
87 ['class_name', 'value', 'virtual'])
88
89def parse_wire_types_data(uclass):
90 if not uclass.virtual:
91 return None
92
Rich Laneb9fab4b2014-03-04 18:44:08 -080093 # Generate a dict of version -> ParseWireTypesVersion
94 versioned = {}
95 for version, ofclass in sorted(uclass.version_classes.items()):
Rich Lanea4b68302014-03-12 15:17:58 -070096 discriminator = ofclass.discriminator
Rich Laneb9fab4b2014-03-04 18:44:08 -080097 subclasses = [ParseWireTypesSubclass(class_name=subclass.name,
98 value=subclass.member_by_name(discriminator.name).value,
99 virtual=subclass.virtual)
100 for subclass in ofclass.protocol.classes if subclass.superclass and subclass.superclass.name == ofclass.name]
101
102 subclasses.sort(key=lambda x: x.value)
103 versioned[version] = ParseWireTypesVersion(discriminator=discriminator,
104 subclasses=subclasses)
105
106 return ParseWireTypesData(class_name=uclass.name,
107 versioned=sorted(versioned.items()))
108
Rich Lanef51062b2014-02-24 23:08:26 -0800109# Output multiple LOCI classes into each C file. This reduces the overhead of
110# parsing header files, which takes longer than compiling the actual code
111# for many classes. It also reduces the compiled code size.
Rich Lanece2e4642013-12-15 12:05:45 -0800112def generate_classes(install_dir):
Rich Lanef51062b2014-02-24 23:08:26 -0800113 for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
114 with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
115 for uclass in chunk:
116 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800117 push_wire_types_data=push_wire_types_data(uclass),
118 parse_wire_types_data=parse_wire_types_data(uclass))
Rich Lanef51062b2014-02-24 23:08:26 -0800119 # Append legacy generated code
120 c_code_gen.gen_new_function_definitions(out, uclass.name)
121 c_code_gen.gen_accessor_definitions(out, uclass.name)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800122
Rich Lane573d2b22013-12-15 13:31:27 -0800123# TODO remove header classes and use the corresponding class instead
124def generate_header_classes(install_dir):
125 for cls in of_g.standard_class_order:
Rich Lanecba60d82014-04-17 16:05:23 -0700126 if cls.find("_header") < 0 or cls in ["of_header", "of_bsn_header", "of_nicira_header"]:
Rich Lane573d2b22013-12-15 13:31:27 -0800127 continue
128 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800129 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800130 push_wire_types_data=None,
131 parse_wire_types_data=None)
Rich Lane573d2b22013-12-15 13:31:27 -0800132 # Append legacy generated code
133 c_code_gen.gen_new_function_definitions(out, cls)
134 c_code_gen.gen_accessor_definitions(out, cls)
135
Rich Lanedef2e512013-12-15 15:54:02 -0800136def generate_classes_header(install_dir):
137 # Collect legacy code
138 tmp = StringIO()
139 c_code_gen.gen_struct_typedefs(tmp)
140 c_code_gen.gen_new_function_declarations(tmp)
141 c_code_gen.gen_accessor_declarations(tmp)
Rich Lanedef2e512013-12-15 15:54:02 -0800142 c_code_gen.gen_generics(tmp)
143
144 with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
145 util.render_template(out, "loci_classes.h",
146 legacy_code=tmp.getvalue())
147
Rich Lane8c4c23f2013-12-15 13:22:13 -0800148def generate_lists(install_dir):
149 for cls in of_g.ordered_list_objects:
150 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane99d9a8d2014-06-13 14:05:10 -0700151 e_cls = loxi_utils.list_to_entry_type(cls)
152 util.render_template(out, "list.c", cls=cls, e_cls=e_cls)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800153 # Append legacy generated code
Rich Laneb604e332013-12-15 13:23:51 -0800154 c_code_gen.gen_new_function_definitions(out, cls)
Rich Lane8a822732013-12-15 14:06:32 -0800155
156def generate_strings(install_dir):
157 object_id_strs = []
158 object_id_strs.append("of_object")
159 object_id_strs.extend(of_g.ordered_messages)
160 object_id_strs.extend(of_g.ordered_non_messages)
161 object_id_strs.extend(of_g.ordered_list_objects)
162 object_id_strs.extend(of_g.ordered_pseudo_objects)
163 object_id_strs.append("of_unknown_object")
164
165 with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
166 util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
Rich Lanecce961d2013-12-15 14:20:42 -0800167
168def generate_init_map(install_dir):
169 with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
170 util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800171
172def generate_type_maps(install_dir):
173 # Collect legacy code
174 tmp = StringIO()
Rich Lanec0e20ff2013-12-15 23:40:31 -0800175 c_type_maps.gen_length_array(tmp)
176 c_type_maps.gen_extra_length_array(tmp)
177
178 with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
179 util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
Rich Lanedc46fe22014-04-03 15:10:38 -0700180
181ClassMetadata = namedtuple('ClassMetadata',
182 ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
183
184def generate_class_metadata(install_dir):
185 with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
186 util.render_template(out, "loci_class_metadata.h")
187
188 with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
189 class_metadata = []
190 for uclass in loxi_globals.unified.classes:
191 wire_length_get = 'NULL'
192 wire_length_set = 'NULL'
193 wire_type_get = 'NULL'
194 wire_type_set = 'NULL'
195
196 if uclass and not uclass.virtual and uclass.has_type_members:
197 wire_type_set = '%s_push_wire_types' % uclass.name
198
199 if uclass.is_message and uclass.name != "of_header":
200 wire_length_get = 'of_object_message_wire_length_get'
201 wire_length_set = 'of_object_message_wire_length_set'
202 elif uclass.is_action:
203 wire_length_set = 'of_tlv16_wire_length_set'
204 wire_length_get = 'of_tlv16_wire_length_get'
205 wire_type_get = 'of_action_wire_object_id_get'
Wilson Ng734a1d62014-04-17 18:34:17 -0700206 elif uclass.is_instanceof('of_bsn_vport'):
207 wire_length_set = 'of_tlv16_wire_length_set'
208 wire_length_get = 'of_tlv16_wire_length_get'
209 wire_type_get = 'of_bsn_vport_wire_object_id_get'
Rich Lanedc46fe22014-04-03 15:10:38 -0700210 elif uclass.is_action_id:
211 wire_length_set = 'of_tlv16_wire_length_set'
212 wire_length_get = 'of_tlv16_wire_length_get'
213 wire_type_get = 'of_action_id_wire_object_id_get'
214 elif uclass.is_instruction:
215 wire_length_set = 'of_tlv16_wire_length_set'
216 wire_length_get = 'of_tlv16_wire_length_get'
217 wire_type_get = 'of_instruction_wire_object_id_get'
218 elif uclass.is_instanceof('of_instruction_id'):
219 wire_length_set = 'of_tlv16_wire_length_set'
220 wire_length_get = 'of_tlv16_wire_length_get'
221 wire_type_get = 'of_instruction_id_wire_object_id_get'
222 elif uclass.is_instanceof('of_queue_prop'):
223 wire_length_set = 'of_tlv16_wire_length_set'
224 wire_length_get = 'of_tlv16_wire_length_get'
225 wire_type_get = 'of_queue_prop_wire_object_id_get'
226 elif uclass.is_instanceof('of_table_feature_prop'):
227 wire_length_set = 'of_tlv16_wire_length_set'
228 wire_length_get = 'of_tlv16_wire_length_get'
229 wire_type_get = 'of_table_feature_prop_wire_object_id_get'
230 elif uclass.is_instanceof('of_meter_band'):
231 wire_length_set = 'of_tlv16_wire_length_set'
232 wire_length_get = 'of_tlv16_wire_length_get'
233 wire_type_get = 'of_meter_band_wire_object_id_get'
234 elif uclass.is_instanceof('of_hello_elem'):
235 wire_length_set = 'of_tlv16_wire_length_set'
236 wire_length_get = 'of_tlv16_wire_length_get'
237 wire_type_get = 'of_hello_elem_wire_object_id_get'
238 elif uclass.is_instanceof('of_bsn_tlv'):
239 wire_length_set = 'of_tlv16_wire_length_set'
240 wire_length_get = 'of_tlv16_wire_length_get'
241 wire_type_get = 'of_bsn_tlv_wire_object_id_get'
242 elif uclass.is_oxm:
243 wire_length_get = 'of_oxm_wire_length_get'
244 wire_type_get = 'of_oxm_wire_object_id_get'
245 elif uclass.name == "of_packet_queue":
246 wire_length_get = 'of_packet_queue_wire_length_get'
247 wire_length_set = 'of_packet_queue_wire_length_set'
Rich Lanedc46fe22014-04-03 15:10:38 -0700248 elif uclass.name == "of_meter_stats":
249 wire_length_get = 'of_meter_stats_wire_length_get'
250 wire_length_set = 'of_meter_stats_wire_length_set'
251 elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
252 "of_flow_stats_entry", "of_bucket", "of_table_features",
253 "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
254 "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
255 "of_bsn_gentable_desc_stats_entry"]:
256 wire_length_get = "of_u16_len_wire_length_get"
257 wire_length_set = "of_u16_len_wire_length_set"
258 elif uclass.name == 'of_match_v3':
259 wire_length_set = 'of_tlv16_wire_length_set'
260 wire_length_get = 'of_tlv16_wire_length_get'
261 wire_type_set = 'of_match_v3_push_wire_types'
262
263 class_metadata.append(ClassMetadata(
264 name=uclass.name,
265 wire_length_get=wire_length_get,
266 wire_length_set=wire_length_set,
267 wire_type_get=wire_type_get,
268 wire_type_set=wire_type_set))
269
270 class_metadata.extend([
271 ClassMetadata(
272 name="of_action_header",
273 wire_length_set='of_tlv16_wire_length_set',
274 wire_length_get='of_tlv16_wire_length_get',
275 wire_type_get='of_action_wire_object_id_get',
276 wire_type_set='NULL'),
277 ClassMetadata(
278 name="of_action_id_header",
279 wire_length_set='of_tlv16_wire_length_set',
280 wire_length_get='of_tlv16_wire_length_get',
281 wire_type_get='of_action_id_wire_object_id_get',
282 wire_type_set='NULL'),
283 ClassMetadata(
Wilson Ng734a1d62014-04-17 18:34:17 -0700284 name="of_bsn_vport_header",
285 wire_length_set='of_tlv16_wire_length_set',
286 wire_length_get='of_tlv16_wire_length_get',
287 wire_type_get='of_bsn_vport_wire_object_id_get',
288 wire_type_set='NULL'),
289 ClassMetadata(
Rich Lanedc46fe22014-04-03 15:10:38 -0700290 name="of_instruction_header",
291 wire_length_set='of_tlv16_wire_length_set',
292 wire_length_get='of_tlv16_wire_length_get',
293 wire_type_get='of_instruction_wire_object_id_get',
294 wire_type_set='NULL'),
295 ClassMetadata(
296 name="of_instruction_id_header",
297 wire_length_set='of_tlv16_wire_length_set',
298 wire_length_get='of_tlv16_wire_length_get',
299 wire_type_get='of_instruction_id_wire_object_id_get',
300 wire_type_set='NULL'),
301 ClassMetadata(
302 name="of_queue_prop_header",
303 wire_length_set='of_tlv16_wire_length_set',
304 wire_length_get='of_tlv16_wire_length_get',
305 wire_type_get='of_queue_prop_wire_object_id_get',
306 wire_type_set='NULL'),
307 ClassMetadata(
308 name="of_table_feature_prop_header",
309 wire_length_set='of_tlv16_wire_length_set',
310 wire_length_get='of_tlv16_wire_length_get',
311 wire_type_get='of_table_feature_prop_wire_object_id_get',
312 wire_type_set='NULL'),
313 ClassMetadata(
314 name="of_meter_band_header",
315 wire_length_set='of_tlv16_wire_length_set',
316 wire_length_get='of_tlv16_wire_length_get',
317 wire_type_get='of_meter_band_wire_object_id_get',
318 wire_type_set='NULL'),
319 ClassMetadata(
320 name="of_hello_elem_header",
321 wire_length_set='of_tlv16_wire_length_set',
322 wire_length_get='of_tlv16_wire_length_get',
323 wire_type_get='of_hello_elem_wire_object_id_get',
324 wire_type_set='NULL'),
325 ClassMetadata(
326 name="of_bsn_tlv_header",
327 wire_length_set='of_tlv16_wire_length_set',
328 wire_length_get='of_tlv16_wire_length_get',
329 wire_type_get='of_bsn_tlv_wire_object_id_get',
330 wire_type_set='NULL'),
331 ClassMetadata(
332 name="of_oxm_header",
333 wire_length_set='NULL',
334 wire_length_get='of_oxm_wire_length_get',
335 wire_type_get='of_oxm_wire_object_id_get',
336 wire_type_set='NULL'),
337 ])
338
339 util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)