blob: f898957726922f07915d5a534d4c3a900cfb37ce [file] [log] [blame]
Andreas Wundsam542a13c2013-11-15 13:28:55 -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"""
29@brief Utilities involving LOXI naming conventions
30
31Utility functions for OpenFlow class generation
32
33These may need to be sorted out into language specific functions
34"""
35
36import sys
37import c_gen.of_g_legacy as of_g
38import tenjin
39from generic_utils import find, memoize
40
41def class_signature(members):
42 """
43 Generate a signature string for a class in canonical form
44
45 @param cls The class whose signature is to be generated
46 """
47 return ";".join([",".join([x["m_type"], x["name"], str(x["offset"])])
48 for x in members])
49
50def type_dec_to_count_base(m_type):
51 """
52 Resolve a type declaration like uint8_t[4] to a count (4) and base_type
53 (uint8_t)
54
55 @param m_type The string type declaration to process
56 """
57 count = 1
58 chk_ar = m_type.split('[')
59 if len(chk_ar) > 1:
60 count_str = chk_ar[1].split(']')[0]
61 if count_str in of_g.ofp_constants:
62 count = of_g.ofp_constants[count_str]
63 else:
64 count = int(count_str)
65 base_type = chk_ar[0]
66 else:
67 base_type = m_type
68 return count, base_type
69
70##
71# Class types:
72#
73# Virtual
74# A virtual class is one which does not have an explicit wire
75# representation. For example, an inheritance super class
76# or a list type.
77#
78# List
79# A list of objects of some other type
80#
81# TLV16
82# The wire represenation starts with 16-bit type and length fields
83#
84# OXM
85# An extensible match object
86#
87# Message
88# A top level OpenFlow message
89#
90#
91
92def class_is_message(cls):
93 """
94 Return True if cls is a message object based on info in unified
95 """
Rich Lanec9c54fe2014-04-23 15:15:09 -070096 return "xid" in of_g.unified[cls]["union"]
Andreas Wundsam542a13c2013-11-15 13:28:55 -080097
98def class_is_tlv16(cls):
99 """
100 Return True if cls_name is an object which uses uint16 for type and length
101 """
102 if cls.find("of_action") == 0: # Includes of_action_id classes
103 return True
104 if cls.find("of_instruction") == 0:
105 return True
106 if cls.find("of_queue_prop") == 0:
107 return True
108 if cls.find("of_table_feature_prop") == 0:
109 return True
110 # *sigh*
111 if cls.find("of_meter_band_stats") == 0: # NOT A TLV
112 return False
113 if cls.find("of_meter_band") == 0:
114 return True
115 if cls.find("of_hello_elem") == 0:
116 return True
117 if cls == "of_match_v3":
118 return True
119 if cls == "of_match_v4":
120 return True
Rich Lane713d9282013-12-30 15:21:35 -0800121 if cls.find("of_bsn_tlv") == 0:
122 return True
Wilson Ngd6181882014-04-14 16:28:35 -0700123 if cls.find("of_bsn_vport") == 0:
124 return True
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800125 return False
126
127def class_is_u16_len(cls):
128 """
129 Return True if cls_name is an object which uses initial uint16 length
130 """
131 return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
xinwuf08ef682013-12-05 18:29:20 -0800132 "of_flow_stats_entry", "of_bucket", "of_table_features",
Rich Lane713d9282013-12-30 15:21:35 -0800133 "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
134 "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
135 "of_bsn_gentable_desc_stats_entry"]
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800136
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800137def class_is_list(cls):
138 """
139 Return True if cls_name is a list object
140 """
141 return (cls.find("of_list_") == 0)
142
143def type_is_of_object(m_type):
144 """
145 Return True if m_type is an OF object type
146 """
147 # Remove _t from the type id and see if key for unified class
148 if m_type[-2:] == "_t":
149 m_type = m_type[:-2]
150 return m_type in of_g.unified
151
152def list_to_entry_type(cls):
153 """
154 Return the entry type for a list
155 """
156 slen = len("of_list_")
157 return "of_" + cls[slen:]
158
159def type_to_short_name(m_type):
160 if m_type in of_g.of_base_types:
161 tname = of_g.of_base_types[m_type]["short_name"]
162 elif m_type in of_g.of_mixed_types:
163 tname = of_g.of_mixed_types[m_type]["short_name"]
164 else:
165 tname = "unknown"
166 return tname
167
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800168def member_to_index(m_name, members):
169 """
170 Given a member name, return the index in the members dict
171 @param m_name The name of the data member to search for
172 @param members The dict of members
173 @return Index if found, -1 not found
174
175 Note we could generate an index when processing the original input
176 """
177 count = 0
178 for d in members:
179 if d["name"] == m_name:
180 return count
181 count += 1
182 return -1
183
184def member_base_type(cls, m_name):
185 """
186 Map a member to its of_ type
187 @param cls The class name
188 @param m_name The name of the member being gotten
189 @return The of_ type of the member
190 """
191 rv = of_g.unified[cls]["union"][m_name]["m_type"]
192 if rv[-2:] == "_t":
193 return rv
194 return rv + "_t"
195
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800196def type_is_scalar(m_type):
197 return m_type in of_g.of_scalar_types
198
199def skip_member_name(name):
200 return name.find("pad") == 0 or name in of_g.skip_members
201
202def enum_name(cls):
203 """
204 Return the name used for an enum identifier for the given class
205 @param cls The class name
206 """
207 return cls.upper()
208
209def class_in_version(cls, ver):
210 """
211 Return boolean indicating if cls is defined for wire version ver
212 """
213
214 return (cls, ver) in of_g.base_length
215
216def instance_to_class(instance, parent):
217 """
218 Return the name of the class for an instance of inheritance type parent
219 """
220 return parent + "_" + instance
221
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800222def class_is_var_len(cls, version):
223 # Match is special case. Only version 1.2 (wire version 3) is var
224 if cls == "of_match":
225 return version == 3
226
227 return not (cls, version) in of_g.is_fixed_length
228
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800229##
230# Is class a flow modify of some sort?
231
232def cls_is_flow_mod(cls):
233 return cls in ["of_flow_mod", "of_flow_modify", "of_flow_add", "of_flow_delete",
234 "of_flow_modify_strict", "of_flow_delete_strict"]
235
236
237def all_member_types_get(cls, version):
238 """
239 Get the members and list of types for members of a given class
240 @param cls The class name to process
241 @param version The version for the class
242 """
243 member_types = []
244
245 if not version in of_g.unified[cls]:
246 return ([], [])
247
248 if "use_version" in of_g.unified[cls][version]:
249 v = of_g.unified[cls][version]["use_version"]
250 members = of_g.unified[cls][v]["members"]
251 else:
252 members = of_g.unified[cls][version]["members"]
253 # Accumulate variables that are supported
254 for member in members:
255 m_type = member["m_type"]
256 m_name = member["name"]
257 if skip_member_name(m_name):
258 continue
259 if not m_type in member_types:
260 member_types.append(m_type)
261
262 return (members, member_types)
263
264def list_name_extract(list_type):
265 """
266 Return the base name for a list object of the given type
267 @param list_type The type of the list as appears in the input,
268 for example list(of_port_desc_t).
269 @return A pair, (list-name, base-type) where list-name is the
270 base name for the list, for example of_list_port_desc, and base-type
271 is the type of list elements like of_port_desc_t
272 """
273 base_type = list_type[5:-1]
274 list_name = base_type
275 if list_name.find("of_") == 0:
276 list_name = list_name[3:]
277 if list_name[-2:] == "_t":
278 list_name = list_name[:-2]
279 list_name = "of_list_" + list_name
280 return (list_name, base_type)
281
282def version_to_name(version):
283 """
284 Convert an integer version to the C macro name
285 """
286 return "OF_" + of_g.version_names[version]
287
288def gen_c_copy_license(out):
289 """
290 Generate the top comments for copyright and license
291 """
292 import c_gen.util
293 c_gen.util.render_template(out, '_copyright.c')
294
295def accessor_returns_error(a_type, m_type):
296 is_var_len = (not type_is_scalar(m_type)) and \
297 [x for x in of_g.of_version_range if class_is_var_len(m_type[:-2], x)] != []
298 if a_type == "set" and is_var_len:
299 return True
300 elif m_type == "of_match_t":
301 return True
302 else:
303 return False