blob: 9af92238d1600f0efe2ee0ad0d65a09b315219b8 [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 Lanebdd8e292013-12-06 17:37:39 -080046
Rich Lanef51062b2014-02-24 23:08:26 -080047CLASS_CHUNK_SIZE = 32
48
Rich Lane22811f52013-12-15 15:28:03 -080049PushWireTypesData = namedtuple('PushWireTypesData',
Rich Lanebdd8e292013-12-06 17:37:39 -080050 ['class_name', 'versioned_type_members'])
51PushWireTypesMember = namedtuple('PushWireTypesMember',
52 ['name', 'offset', 'length', 'value'])
53
Rich Lane22811f52013-12-15 15:28:03 -080054def push_wire_types_data(uclass):
55 if uclass.virtual or not uclass.has_type_members:
56 return None
Rich Lanebdd8e292013-12-06 17:37:39 -080057
Rich Lane22811f52013-12-15 15:28:03 -080058 # Generate a dict of version -> list of PushWireTypesMember
59 type_members_by_version = {}
60 for version, ofclass in sorted(uclass.version_classes.items()):
61 pwtms = []
62 for m in ofclass.members:
63 if isinstance(m, ir.OFTypeMember):
64 if m.name == "version" and m.value == version.wire_version:
65 # Special case for version
66 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
67 else:
Rich Laned0c58712013-12-18 10:02:47 -080068 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
Rich Lane22811f52013-12-15 15:28:03 -080069 type_members_by_version[version] = pwtms
Rich Lanebdd8e292013-12-06 17:37:39 -080070
Rich Lane22811f52013-12-15 15:28:03 -080071 # Merge versions with identical type members
72 all_versions = sorted(type_members_by_version.keys())
73 versioned_type_members = []
74 for pwtms, versions in groupby(all_versions, type_members_by_version.get):
75 versioned_type_members.append((pwtms, list(versions)))
Rich Lanebdd8e292013-12-06 17:37:39 -080076
Rich Lane22811f52013-12-15 15:28:03 -080077 return PushWireTypesData(
78 class_name=uclass.name,
79 versioned_type_members=versioned_type_members)
Rich Lanece2e4642013-12-15 12:05:45 -080080
Rich Laneb9fab4b2014-03-04 18:44:08 -080081ParseWireTypesData = namedtuple('ParseWireTypesData',
82 ['class_name', 'versioned'])
83ParseWireTypesVersion = namedtuple('ParseWireTypesVersion',
84 ['discriminator', 'subclasses'])
85ParseWireTypesSubclass = namedtuple('ParseWireTypesSubclass',
86 ['class_name', 'value', 'virtual'])
87
88def parse_wire_types_data(uclass):
89 if not uclass.virtual:
90 return None
91
Rich Laneb9fab4b2014-03-04 18:44:08 -080092 # Generate a dict of version -> ParseWireTypesVersion
93 versioned = {}
94 for version, ofclass in sorted(uclass.version_classes.items()):
Rich Lanea4b68302014-03-12 15:17:58 -070095 discriminator = ofclass.discriminator
Rich Laneb9fab4b2014-03-04 18:44:08 -080096 subclasses = [ParseWireTypesSubclass(class_name=subclass.name,
97 value=subclass.member_by_name(discriminator.name).value,
98 virtual=subclass.virtual)
99 for subclass in ofclass.protocol.classes if subclass.superclass and subclass.superclass.name == ofclass.name]
100
101 subclasses.sort(key=lambda x: x.value)
102 versioned[version] = ParseWireTypesVersion(discriminator=discriminator,
103 subclasses=subclasses)
104
105 return ParseWireTypesData(class_name=uclass.name,
106 versioned=sorted(versioned.items()))
107
Rich Lanef51062b2014-02-24 23:08:26 -0800108# Output multiple LOCI classes into each C file. This reduces the overhead of
109# parsing header files, which takes longer than compiling the actual code
110# for many classes. It also reduces the compiled code size.
Rich Lanece2e4642013-12-15 12:05:45 -0800111def generate_classes(install_dir):
Rich Lanef51062b2014-02-24 23:08:26 -0800112 for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
113 with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
114 for uclass in chunk:
115 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800116 push_wire_types_data=push_wire_types_data(uclass),
117 parse_wire_types_data=parse_wire_types_data(uclass))
Rich Lanef51062b2014-02-24 23:08:26 -0800118 # Append legacy generated code
119 c_code_gen.gen_new_function_definitions(out, uclass.name)
120 c_code_gen.gen_accessor_definitions(out, uclass.name)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800121
Rich Lane573d2b22013-12-15 13:31:27 -0800122# TODO remove header classes and use the corresponding class instead
123def generate_header_classes(install_dir):
124 for cls in of_g.standard_class_order:
Rich Lanecba60d82014-04-17 16:05:23 -0700125 if cls.find("_header") < 0 or cls in ["of_header", "of_bsn_header", "of_nicira_header"]:
Rich Lane573d2b22013-12-15 13:31:27 -0800126 continue
127 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800128 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800129 push_wire_types_data=None,
130 parse_wire_types_data=None)
Rich Lane573d2b22013-12-15 13:31:27 -0800131 # Append legacy generated code
132 c_code_gen.gen_new_function_definitions(out, cls)
133 c_code_gen.gen_accessor_definitions(out, cls)
134
Rich Lanedef2e512013-12-15 15:54:02 -0800135def generate_classes_header(install_dir):
136 # Collect legacy code
137 tmp = StringIO()
138 c_code_gen.gen_struct_typedefs(tmp)
139 c_code_gen.gen_new_function_declarations(tmp)
140 c_code_gen.gen_accessor_declarations(tmp)
Rich Lanedef2e512013-12-15 15:54:02 -0800141 c_code_gen.gen_generics(tmp)
142
143 with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
144 util.render_template(out, "loci_classes.h",
145 legacy_code=tmp.getvalue())
146
Rich Lane8c4c23f2013-12-15 13:22:13 -0800147def generate_lists(install_dir):
148 for cls in of_g.ordered_list_objects:
149 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800150 util.render_template(out, "class.c",
Rich Laneb9fab4b2014-03-04 18:44:08 -0800151 push_wire_types_data=None,
152 parse_wire_types_data=None)
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 Lane8c4c23f2013-12-15 13:22:13 -0800155 c_code_gen.gen_list_accessors(out, cls)
Rich Lane8a822732013-12-15 14:06:32 -0800156
157def generate_strings(install_dir):
158 object_id_strs = []
159 object_id_strs.append("of_object")
160 object_id_strs.extend(of_g.ordered_messages)
161 object_id_strs.extend(of_g.ordered_non_messages)
162 object_id_strs.extend(of_g.ordered_list_objects)
163 object_id_strs.extend(of_g.ordered_pseudo_objects)
164 object_id_strs.append("of_unknown_object")
165
166 with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
167 util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
Rich Lanecce961d2013-12-15 14:20:42 -0800168
169def generate_init_map(install_dir):
170 with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
171 util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800172
173def generate_type_maps(install_dir):
174 # Collect legacy code
175 tmp = StringIO()
176 c_type_maps.gen_type_to_obj_map_functions(tmp)
177 c_type_maps.gen_type_maps(tmp)
178 c_type_maps.gen_length_array(tmp)
179 c_type_maps.gen_extra_length_array(tmp)
180
181 with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
182 util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
Rich Lanedc46fe22014-04-03 15:10:38 -0700183
184ClassMetadata = namedtuple('ClassMetadata',
185 ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
186
187def generate_class_metadata(install_dir):
188 with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
189 util.render_template(out, "loci_class_metadata.h")
190
191 with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
192 class_metadata = []
193 for uclass in loxi_globals.unified.classes:
194 wire_length_get = 'NULL'
195 wire_length_set = 'NULL'
196 wire_type_get = 'NULL'
197 wire_type_set = 'NULL'
198
199 if uclass and not uclass.virtual and uclass.has_type_members:
200 wire_type_set = '%s_push_wire_types' % uclass.name
201
202 if uclass.is_message and uclass.name != "of_header":
203 wire_length_get = 'of_object_message_wire_length_get'
204 wire_length_set = 'of_object_message_wire_length_set'
205 elif uclass.is_action:
206 wire_length_set = 'of_tlv16_wire_length_set'
207 wire_length_get = 'of_tlv16_wire_length_get'
208 wire_type_get = 'of_action_wire_object_id_get'
Wilson Ng734a1d62014-04-17 18:34:17 -0700209 elif uclass.is_instanceof('of_bsn_vport'):
210 wire_length_set = 'of_tlv16_wire_length_set'
211 wire_length_get = 'of_tlv16_wire_length_get'
212 wire_type_get = 'of_bsn_vport_wire_object_id_get'
Rich Lanedc46fe22014-04-03 15:10:38 -0700213 elif uclass.is_action_id:
214 wire_length_set = 'of_tlv16_wire_length_set'
215 wire_length_get = 'of_tlv16_wire_length_get'
216 wire_type_get = 'of_action_id_wire_object_id_get'
217 elif uclass.is_instruction:
218 wire_length_set = 'of_tlv16_wire_length_set'
219 wire_length_get = 'of_tlv16_wire_length_get'
220 wire_type_get = 'of_instruction_wire_object_id_get'
221 elif uclass.is_instanceof('of_instruction_id'):
222 wire_length_set = 'of_tlv16_wire_length_set'
223 wire_length_get = 'of_tlv16_wire_length_get'
224 wire_type_get = 'of_instruction_id_wire_object_id_get'
225 elif uclass.is_instanceof('of_queue_prop'):
226 wire_length_set = 'of_tlv16_wire_length_set'
227 wire_length_get = 'of_tlv16_wire_length_get'
228 wire_type_get = 'of_queue_prop_wire_object_id_get'
229 elif uclass.is_instanceof('of_table_feature_prop'):
230 wire_length_set = 'of_tlv16_wire_length_set'
231 wire_length_get = 'of_tlv16_wire_length_get'
232 wire_type_get = 'of_table_feature_prop_wire_object_id_get'
233 elif uclass.is_instanceof('of_meter_band'):
234 wire_length_set = 'of_tlv16_wire_length_set'
235 wire_length_get = 'of_tlv16_wire_length_get'
236 wire_type_get = 'of_meter_band_wire_object_id_get'
237 elif uclass.is_instanceof('of_hello_elem'):
238 wire_length_set = 'of_tlv16_wire_length_set'
239 wire_length_get = 'of_tlv16_wire_length_get'
240 wire_type_get = 'of_hello_elem_wire_object_id_get'
241 elif uclass.is_instanceof('of_bsn_tlv'):
242 wire_length_set = 'of_tlv16_wire_length_set'
243 wire_length_get = 'of_tlv16_wire_length_get'
244 wire_type_get = 'of_bsn_tlv_wire_object_id_get'
245 elif uclass.is_oxm:
246 wire_length_get = 'of_oxm_wire_length_get'
247 wire_type_get = 'of_oxm_wire_object_id_get'
248 elif uclass.name == "of_packet_queue":
249 wire_length_get = 'of_packet_queue_wire_length_get'
250 wire_length_set = 'of_packet_queue_wire_length_set'
Rich Lanedc46fe22014-04-03 15:10:38 -0700251 elif uclass.name == "of_meter_stats":
252 wire_length_get = 'of_meter_stats_wire_length_get'
253 wire_length_set = 'of_meter_stats_wire_length_set'
254 elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
255 "of_flow_stats_entry", "of_bucket", "of_table_features",
256 "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
257 "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
258 "of_bsn_gentable_desc_stats_entry"]:
259 wire_length_get = "of_u16_len_wire_length_get"
260 wire_length_set = "of_u16_len_wire_length_set"
261 elif uclass.name == 'of_match_v3':
262 wire_length_set = 'of_tlv16_wire_length_set'
263 wire_length_get = 'of_tlv16_wire_length_get'
264 wire_type_set = 'of_match_v3_push_wire_types'
265
266 class_metadata.append(ClassMetadata(
267 name=uclass.name,
268 wire_length_get=wire_length_get,
269 wire_length_set=wire_length_set,
270 wire_type_get=wire_type_get,
271 wire_type_set=wire_type_set))
272
273 class_metadata.extend([
274 ClassMetadata(
275 name="of_action_header",
276 wire_length_set='of_tlv16_wire_length_set',
277 wire_length_get='of_tlv16_wire_length_get',
278 wire_type_get='of_action_wire_object_id_get',
279 wire_type_set='NULL'),
280 ClassMetadata(
281 name="of_action_id_header",
282 wire_length_set='of_tlv16_wire_length_set',
283 wire_length_get='of_tlv16_wire_length_get',
284 wire_type_get='of_action_id_wire_object_id_get',
285 wire_type_set='NULL'),
286 ClassMetadata(
Wilson Ng734a1d62014-04-17 18:34:17 -0700287 name="of_bsn_vport_header",
288 wire_length_set='of_tlv16_wire_length_set',
289 wire_length_get='of_tlv16_wire_length_get',
290 wire_type_get='of_bsn_vport_wire_object_id_get',
291 wire_type_set='NULL'),
292 ClassMetadata(
Rich Lanedc46fe22014-04-03 15:10:38 -0700293 name="of_instruction_header",
294 wire_length_set='of_tlv16_wire_length_set',
295 wire_length_get='of_tlv16_wire_length_get',
296 wire_type_get='of_instruction_wire_object_id_get',
297 wire_type_set='NULL'),
298 ClassMetadata(
299 name="of_instruction_id_header",
300 wire_length_set='of_tlv16_wire_length_set',
301 wire_length_get='of_tlv16_wire_length_get',
302 wire_type_get='of_instruction_id_wire_object_id_get',
303 wire_type_set='NULL'),
304 ClassMetadata(
305 name="of_queue_prop_header",
306 wire_length_set='of_tlv16_wire_length_set',
307 wire_length_get='of_tlv16_wire_length_get',
308 wire_type_get='of_queue_prop_wire_object_id_get',
309 wire_type_set='NULL'),
310 ClassMetadata(
311 name="of_table_feature_prop_header",
312 wire_length_set='of_tlv16_wire_length_set',
313 wire_length_get='of_tlv16_wire_length_get',
314 wire_type_get='of_table_feature_prop_wire_object_id_get',
315 wire_type_set='NULL'),
316 ClassMetadata(
317 name="of_meter_band_header",
318 wire_length_set='of_tlv16_wire_length_set',
319 wire_length_get='of_tlv16_wire_length_get',
320 wire_type_get='of_meter_band_wire_object_id_get',
321 wire_type_set='NULL'),
322 ClassMetadata(
323 name="of_hello_elem_header",
324 wire_length_set='of_tlv16_wire_length_set',
325 wire_length_get='of_tlv16_wire_length_get',
326 wire_type_get='of_hello_elem_wire_object_id_get',
327 wire_type_set='NULL'),
328 ClassMetadata(
329 name="of_bsn_tlv_header",
330 wire_length_set='of_tlv16_wire_length_set',
331 wire_length_get='of_tlv16_wire_length_get',
332 wire_type_get='of_bsn_tlv_wire_object_id_get',
333 wire_type_set='NULL'),
334 ClassMetadata(
335 name="of_oxm_header",
336 wire_length_set='NULL',
337 wire_length_get='of_oxm_wire_length_get',
338 wire_type_get='of_oxm_wire_object_id_get',
339 wire_type_set='NULL'),
340 ])
341
342 util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)