blob: ea05826f62bafcb0ef0ee952a6e38d53b07dfe53 [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 Lane573d2b22013-12-15 13:31:27 -0800124# TODO remove header classes and use the corresponding class instead
125def generate_header_classes(install_dir):
126 for cls in of_g.standard_class_order:
Rich Lanecba60d82014-04-17 16:05:23 -0700127 if cls.find("_header") < 0 or cls in ["of_header", "of_bsn_header", "of_nicira_header"]:
Rich Lane573d2b22013-12-15 13:31:27 -0800128 continue
129 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800130 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800131 push_wire_types_data=None,
132 parse_wire_types_data=None)
Rich Lane573d2b22013-12-15 13:31:27 -0800133 # Append legacy generated code
134 c_code_gen.gen_new_function_definitions(out, cls)
135 c_code_gen.gen_accessor_definitions(out, cls)
136
Rich Lanedef2e512013-12-15 15:54:02 -0800137def generate_classes_header(install_dir):
138 # Collect legacy code
139 tmp = StringIO()
140 c_code_gen.gen_struct_typedefs(tmp)
141 c_code_gen.gen_new_function_declarations(tmp)
142 c_code_gen.gen_accessor_declarations(tmp)
Rich Lanedef2e512013-12-15 15:54:02 -0800143 c_code_gen.gen_generics(tmp)
144
145 with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
146 util.render_template(out, "loci_classes.h",
147 legacy_code=tmp.getvalue())
148
Rich Lane8c4c23f2013-12-15 13:22:13 -0800149def generate_lists(install_dir):
Rich Lane2cc2b862014-06-13 14:50:17 -0700150 # Collect all the lists in use
151 list_oftypes = set()
152 for uclass in loxi_globals.unified.classes:
Rich Lanedeb96752014-06-25 22:27:51 -0700153 for ofclass in uclass.version_classes.values():
Rich Lane2cc2b862014-06-13 14:50:17 -0700154 for m in ofclass.members:
Rich Lanedeb96752014-06-25 22:27:51 -0700155 if isinstance(m, ir.OFDataMember) and \
156 loxi_utils.oftype_is_list(m.oftype):
157 list_oftypes.add(m.oftype)
Rich Lane2cc2b862014-06-13 14:50:17 -0700158
159 for oftype in sorted(list(list_oftypes)):
160 cls, e_cls = loxi_utils_legacy.list_name_extract(oftype)
161 e_cls = e_cls[:-2]
Rich Lane83f958d2014-06-13 15:01:40 -0700162 e_uclass = loxi_globals.unified.class_by_name(e_cls)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800163 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane83f958d2014-06-13 15:01:40 -0700164 util.render_template(out, "list.c", cls=cls, e_cls=e_cls, e_uclass=e_uclass,
Rich Lanebbf5e1d2014-06-13 15:34:21 -0700165 wire_length_get=class_metadata_dict[e_cls].wire_length_get)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800166 # Append legacy generated code
Rich Laneb604e332013-12-15 13:23:51 -0800167 c_code_gen.gen_new_function_definitions(out, cls)
Rich Lane8a822732013-12-15 14:06:32 -0800168
169def generate_strings(install_dir):
170 object_id_strs = []
171 object_id_strs.append("of_object")
172 object_id_strs.extend(of_g.ordered_messages)
173 object_id_strs.extend(of_g.ordered_non_messages)
174 object_id_strs.extend(of_g.ordered_list_objects)
175 object_id_strs.extend(of_g.ordered_pseudo_objects)
176 object_id_strs.append("of_unknown_object")
177
178 with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
179 util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
Rich Lanecce961d2013-12-15 14:20:42 -0800180
181def generate_init_map(install_dir):
182 with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
183 util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800184
185def generate_type_maps(install_dir):
186 # Collect legacy code
187 tmp = StringIO()
Rich Lanec0e20ff2013-12-15 23:40:31 -0800188 c_type_maps.gen_length_array(tmp)
189 c_type_maps.gen_extra_length_array(tmp)
190
191 with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
192 util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
Rich Lanedc46fe22014-04-03 15:10:38 -0700193
194ClassMetadata = namedtuple('ClassMetadata',
195 ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
196
Rich Lane08c9f3a2014-06-13 11:24:37 -0700197class_metadata = []
198class_metadata_dict = {}
199
200def build_class_metadata():
201 for uclass in loxi_globals.unified.classes:
202 wire_length_get = 'NULL'
203 wire_length_set = 'NULL'
204 wire_type_get = 'NULL'
205 wire_type_set = 'NULL'
206
207 if uclass and not uclass.virtual and uclass.has_type_members:
208 wire_type_set = '%s_push_wire_types' % uclass.name
209
210 if uclass.is_message:
211 wire_length_get = 'of_object_message_wire_length_get'
212 wire_length_set = 'of_object_message_wire_length_set'
213 elif uclass.is_action:
214 wire_length_set = 'of_tlv16_wire_length_set'
215 wire_length_get = 'of_tlv16_wire_length_get'
216 wire_type_get = 'of_action_wire_object_id_get'
217 elif uclass.is_instanceof('of_bsn_vport'):
218 wire_length_set = 'of_tlv16_wire_length_set'
219 wire_length_get = 'of_tlv16_wire_length_get'
220 wire_type_get = 'of_bsn_vport_wire_object_id_get'
221 elif uclass.is_action_id:
222 wire_length_set = 'of_tlv16_wire_length_set'
223 wire_length_get = 'of_tlv16_wire_length_get'
224 wire_type_get = 'of_action_id_wire_object_id_get'
225 elif uclass.is_instruction:
226 wire_length_set = 'of_tlv16_wire_length_set'
227 wire_length_get = 'of_tlv16_wire_length_get'
228 wire_type_get = 'of_instruction_wire_object_id_get'
229 elif uclass.is_instanceof('of_instruction_id'):
230 wire_length_set = 'of_tlv16_wire_length_set'
231 wire_length_get = 'of_tlv16_wire_length_get'
232 wire_type_get = 'of_instruction_id_wire_object_id_get'
233 elif uclass.is_instanceof('of_queue_prop'):
234 wire_length_set = 'of_tlv16_wire_length_set'
235 wire_length_get = 'of_tlv16_wire_length_get'
236 wire_type_get = 'of_queue_prop_wire_object_id_get'
237 elif uclass.is_instanceof('of_table_feature_prop'):
238 wire_length_set = 'of_tlv16_wire_length_set'
239 wire_length_get = 'of_tlv16_wire_length_get'
240 wire_type_get = 'of_table_feature_prop_wire_object_id_get'
241 elif uclass.is_instanceof('of_meter_band'):
242 wire_length_set = 'of_tlv16_wire_length_set'
243 wire_length_get = 'of_tlv16_wire_length_get'
244 wire_type_get = 'of_meter_band_wire_object_id_get'
245 elif uclass.is_instanceof('of_hello_elem'):
246 wire_length_set = 'of_tlv16_wire_length_set'
247 wire_length_get = 'of_tlv16_wire_length_get'
248 wire_type_get = 'of_hello_elem_wire_object_id_get'
249 elif uclass.is_instanceof('of_bsn_tlv'):
250 wire_length_set = 'of_tlv16_wire_length_set'
251 wire_length_get = 'of_tlv16_wire_length_get'
252 wire_type_get = 'of_bsn_tlv_wire_object_id_get'
253 elif uclass.is_oxm:
254 wire_length_get = 'of_oxm_wire_length_get'
255 wire_type_get = 'of_oxm_wire_object_id_get'
256 elif uclass.name == "of_packet_queue":
257 wire_length_get = 'of_packet_queue_wire_length_get'
258 wire_length_set = 'of_packet_queue_wire_length_set'
259 elif uclass.name == "of_meter_stats":
260 wire_length_get = 'of_meter_stats_wire_length_get'
261 wire_length_set = 'of_meter_stats_wire_length_set'
262 elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
263 "of_flow_stats_entry", "of_bucket", "of_table_features",
264 "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
265 "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
Ken Chiang78354872014-06-26 14:45:42 -0700266 "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]:
Rich Lane08c9f3a2014-06-13 11:24:37 -0700267 wire_length_get = "of_u16_len_wire_length_get"
268 wire_length_set = "of_u16_len_wire_length_set"
269 elif uclass.name == 'of_match_v3':
270 wire_length_set = 'of_tlv16_wire_length_set'
271 wire_length_get = 'of_tlv16_wire_length_get'
272 wire_type_set = 'of_match_v3_push_wire_types'
273
274 class_metadata.append(ClassMetadata(
275 name=uclass.name,
276 wire_length_get=wire_length_get,
277 wire_length_set=wire_length_set,
278 wire_type_get=wire_type_get,
279 wire_type_set=wire_type_set))
280
281 class_metadata.extend([
282 ClassMetadata(
283 name="of_action_header",
284 wire_length_set='of_tlv16_wire_length_set',
285 wire_length_get='of_tlv16_wire_length_get',
286 wire_type_get='of_action_wire_object_id_get',
287 wire_type_set='NULL'),
288 ClassMetadata(
289 name="of_action_id_header",
290 wire_length_set='of_tlv16_wire_length_set',
291 wire_length_get='of_tlv16_wire_length_get',
292 wire_type_get='of_action_id_wire_object_id_get',
293 wire_type_set='NULL'),
294 ClassMetadata(
295 name="of_bsn_vport_header",
296 wire_length_set='of_tlv16_wire_length_set',
297 wire_length_get='of_tlv16_wire_length_get',
298 wire_type_get='of_bsn_vport_wire_object_id_get',
299 wire_type_set='NULL'),
300 ClassMetadata(
301 name="of_instruction_header",
302 wire_length_set='of_tlv16_wire_length_set',
303 wire_length_get='of_tlv16_wire_length_get',
304 wire_type_get='of_instruction_wire_object_id_get',
305 wire_type_set='NULL'),
306 ClassMetadata(
307 name="of_instruction_id_header",
308 wire_length_set='of_tlv16_wire_length_set',
309 wire_length_get='of_tlv16_wire_length_get',
310 wire_type_get='of_instruction_id_wire_object_id_get',
311 wire_type_set='NULL'),
312 ClassMetadata(
313 name="of_queue_prop_header",
314 wire_length_set='of_tlv16_wire_length_set',
315 wire_length_get='of_tlv16_wire_length_get',
316 wire_type_get='of_queue_prop_wire_object_id_get',
317 wire_type_set='NULL'),
318 ClassMetadata(
319 name="of_table_feature_prop_header",
320 wire_length_set='of_tlv16_wire_length_set',
321 wire_length_get='of_tlv16_wire_length_get',
322 wire_type_get='of_table_feature_prop_wire_object_id_get',
323 wire_type_set='NULL'),
324 ClassMetadata(
325 name="of_meter_band_header",
326 wire_length_set='of_tlv16_wire_length_set',
327 wire_length_get='of_tlv16_wire_length_get',
328 wire_type_get='of_meter_band_wire_object_id_get',
329 wire_type_set='NULL'),
330 ClassMetadata(
331 name="of_hello_elem_header",
332 wire_length_set='of_tlv16_wire_length_set',
333 wire_length_get='of_tlv16_wire_length_get',
334 wire_type_get='of_hello_elem_wire_object_id_get',
335 wire_type_set='NULL'),
336 ClassMetadata(
337 name="of_bsn_tlv_header",
338 wire_length_set='of_tlv16_wire_length_set',
339 wire_length_get='of_tlv16_wire_length_get',
340 wire_type_get='of_bsn_tlv_wire_object_id_get',
341 wire_type_set='NULL'),
342 ClassMetadata(
343 name="of_oxm_header",
344 wire_length_set='NULL',
345 wire_length_get='of_oxm_wire_length_get',
346 wire_type_get='of_oxm_wire_object_id_get',
347 wire_type_set='NULL'),
348 ])
349
350 for metadata in class_metadata:
351 class_metadata_dict[metadata.name] = metadata
352
Rich Lanedc46fe22014-04-03 15:10:38 -0700353def generate_class_metadata(install_dir):
354 with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
355 util.render_template(out, "loci_class_metadata.h")
356
357 with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
Rich Lanedc46fe22014-04-03 15:10:38 -0700358 util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)