blob: 5f3214a86717cbc452e7ef5e793d427c983bde02 [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
Rich Lane90409cc2014-10-13 11:18:02 -070040import loxi_globals
41from loxi_ir import ir
Andreas Wundsam542a13c2013-11-15 13:28:55 -080042
43def class_signature(members):
44 """
45 Generate a signature string for a class in canonical form
46
47 @param cls The class whose signature is to be generated
48 """
49 return ";".join([",".join([x["m_type"], x["name"], str(x["offset"])])
50 for x in members])
51
52def type_dec_to_count_base(m_type):
53 """
54 Resolve a type declaration like uint8_t[4] to a count (4) and base_type
55 (uint8_t)
56
57 @param m_type The string type declaration to process
58 """
59 count = 1
60 chk_ar = m_type.split('[')
61 if len(chk_ar) > 1:
62 count_str = chk_ar[1].split(']')[0]
63 if count_str in of_g.ofp_constants:
64 count = of_g.ofp_constants[count_str]
65 else:
66 count = int(count_str)
67 base_type = chk_ar[0]
68 else:
69 base_type = m_type
70 return count, base_type
71
72##
73# Class types:
74#
75# Virtual
76# A virtual class is one which does not have an explicit wire
77# representation. For example, an inheritance super class
78# or a list type.
79#
80# List
81# A list of objects of some other type
82#
83# TLV16
84# The wire represenation starts with 16-bit type and length fields
85#
86# OXM
87# An extensible match object
88#
89# Message
90# A top level OpenFlow message
91#
92#
93
94def class_is_message(cls):
95 """
96 Return True if cls is a message object based on info in unified
97 """
Rich Lanec9c54fe2014-04-23 15:15:09 -070098 return "xid" in of_g.unified[cls]["union"]
Andreas Wundsam542a13c2013-11-15 13:28:55 -080099
100def class_is_tlv16(cls):
101 """
102 Return True if cls_name is an object which uses uint16 for type and length
103 """
Rich Lane90409cc2014-10-13 11:18:02 -0700104
105 ofclass = loxi_globals.unified.class_by_name(cls)
106 if not ofclass:
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800107 return False
Rich Lane90409cc2014-10-13 11:18:02 -0700108
109 if len(ofclass.members) < 2:
110 return False
111
112 m1 = ofclass.members[0]
113 m2 = ofclass.members[1]
114
115 if not (isinstance(m1, ir.OFTypeMember) or isinstance(m1, ir.OFDiscriminatorMember)):
116 return False
117
118 if not isinstance(m2, ir.OFLengthMember):
119 return False
120
121 if m1.oftype != "uint16_t" or m2.oftype != "uint16_t":
122 return False
123
124 return True
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800125
126def class_is_u16_len(cls):
127 """
128 Return True if cls_name is an object which uses initial uint16 length
129 """
130 return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
xinwuf08ef682013-12-05 18:29:20 -0800131 "of_flow_stats_entry", "of_bucket", "of_table_features",
Rich Lane713d9282013-12-30 15:21:35 -0800132 "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
133 "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
Ken Chiang78354872014-06-26 14:45:42 -0700134 "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800135
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800136def class_is_list(cls):
137 """
138 Return True if cls_name is a list object
139 """
140 return (cls.find("of_list_") == 0)
141
142def type_is_of_object(m_type):
143 """
144 Return True if m_type is an OF object type
145 """
146 # Remove _t from the type id and see if key for unified class
147 if m_type[-2:] == "_t":
148 m_type = m_type[:-2]
149 return m_type in of_g.unified
150
151def list_to_entry_type(cls):
152 """
153 Return the entry type for a list
154 """
155 slen = len("of_list_")
156 return "of_" + cls[slen:]
157
158def type_to_short_name(m_type):
159 if m_type in of_g.of_base_types:
160 tname = of_g.of_base_types[m_type]["short_name"]
161 elif m_type in of_g.of_mixed_types:
162 tname = of_g.of_mixed_types[m_type]["short_name"]
163 else:
164 tname = "unknown"
165 return tname
166
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800167def member_to_index(m_name, members):
168 """
169 Given a member name, return the index in the members dict
170 @param m_name The name of the data member to search for
171 @param members The dict of members
172 @return Index if found, -1 not found
173
174 Note we could generate an index when processing the original input
175 """
176 count = 0
177 for d in members:
178 if d["name"] == m_name:
179 return count
180 count += 1
181 return -1
182
183def member_base_type(cls, m_name):
184 """
185 Map a member to its of_ type
186 @param cls The class name
187 @param m_name The name of the member being gotten
188 @return The of_ type of the member
189 """
190 rv = of_g.unified[cls]["union"][m_name]["m_type"]
191 if rv[-2:] == "_t":
192 return rv
193 return rv + "_t"
194
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800195def type_is_scalar(m_type):
196 return m_type in of_g.of_scalar_types
197
198def skip_member_name(name):
199 return name.find("pad") == 0 or name in of_g.skip_members
200
201def enum_name(cls):
202 """
203 Return the name used for an enum identifier for the given class
204 @param cls The class name
205 """
206 return cls.upper()
207
208def class_in_version(cls, ver):
209 """
210 Return boolean indicating if cls is defined for wire version ver
211 """
212
213 return (cls, ver) in of_g.base_length
214
215def instance_to_class(instance, parent):
216 """
217 Return the name of the class for an instance of inheritance type parent
218 """
219 return parent + "_" + instance
220
Rich Laneee60d4e2014-10-12 20:08:24 -0700221def class_to_instance(cls, base_cls):
222 assert cls.startswith(base_cls + '_')
223 return cls[len(base_cls)+1:]
224
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800225def class_is_var_len(cls, version):
226 # Match is special case. Only version 1.2 (wire version 3) is var
227 if cls == "of_match":
228 return version == 3
229
230 return not (cls, version) in of_g.is_fixed_length
231
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800232##
233# Is class a flow modify of some sort?
234
235def cls_is_flow_mod(cls):
236 return cls in ["of_flow_mod", "of_flow_modify", "of_flow_add", "of_flow_delete",
237 "of_flow_modify_strict", "of_flow_delete_strict"]
238
239
240def all_member_types_get(cls, version):
241 """
242 Get the members and list of types for members of a given class
243 @param cls The class name to process
244 @param version The version for the class
245 """
246 member_types = []
247
248 if not version in of_g.unified[cls]:
249 return ([], [])
250
251 if "use_version" in of_g.unified[cls][version]:
252 v = of_g.unified[cls][version]["use_version"]
253 members = of_g.unified[cls][v]["members"]
254 else:
255 members = of_g.unified[cls][version]["members"]
256 # Accumulate variables that are supported
257 for member in members:
258 m_type = member["m_type"]
259 m_name = member["name"]
260 if skip_member_name(m_name):
261 continue
262 if not m_type in member_types:
263 member_types.append(m_type)
264
265 return (members, member_types)
266
267def list_name_extract(list_type):
268 """
269 Return the base name for a list object of the given type
270 @param list_type The type of the list as appears in the input,
271 for example list(of_port_desc_t).
272 @return A pair, (list-name, base-type) where list-name is the
273 base name for the list, for example of_list_port_desc, and base-type
274 is the type of list elements like of_port_desc_t
275 """
276 base_type = list_type[5:-1]
277 list_name = base_type
278 if list_name.find("of_") == 0:
279 list_name = list_name[3:]
280 if list_name[-2:] == "_t":
281 list_name = list_name[:-2]
282 list_name = "of_list_" + list_name
283 return (list_name, base_type)
284
285def version_to_name(version):
286 """
287 Convert an integer version to the C macro name
288 """
Rich Lanef1a89842014-10-12 10:04:13 -0700289 return of_g.of_version_wire2name[version]
Andreas Wundsam542a13c2013-11-15 13:28:55 -0800290
291def gen_c_copy_license(out):
292 """
293 Generate the top comments for copyright and license
294 """
295 import c_gen.util
296 c_gen.util.render_template(out, '_copyright.c')
297
298def accessor_returns_error(a_type, m_type):
299 is_var_len = (not type_is_scalar(m_type)) and \
300 [x for x in of_g.of_version_range if class_is_var_len(m_type[:-2], x)] != []
301 if a_type == "set" and is_var_len:
302 return True
303 elif m_type == "of_match_t":
304 return True
305 else:
306 return False