blob: 46b798173f59c3a377f2a292a40ebaed11f6f9ed [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# 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
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsam43526532013-08-01 22:03:50 -070050 enum_blacklist = set(("OFDefinitions",))
51 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsambe168f72013-08-03 22:49:35 -070052 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
53 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070054 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
55 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsam001b1822013-08-02 22:25:55 -070056 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070057
Andreas Wundsam2be7da52013-08-22 07:34:25 -070058 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070059 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
60 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
61 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
62 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
63 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
64 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
65 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
66 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
67 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
68 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
69 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
70 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
71 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
72 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
73 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
74 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
75 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
76 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
77 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
78 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
79 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
80 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
81 "OFOxmIpv4Src": OxmMapEntry("IPv4", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4", "IPV4_DST", True),
85 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
86 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
87 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
88 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
89 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
90 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
91 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
92 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
93 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
94 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
95 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
96 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
97 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
98 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
99 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
100 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
101 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
102 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
103 "OFOxmArpSpa": OxmMapEntry("IPv4", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4", "ARP_TPA", True),
107 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
108 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
109 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
110 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
111 "OFOxmIpv6Src": OxmMapEntry("IPv6", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6", "IPV6_DST", True),
115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True) }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700117
Andreas Wundsam27303462013-07-16 12:52:35 -0700118 @property
119 @memoize
120 def versions(self):
121 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
122
123 @property
124 @memoize
125 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700126 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700127
128 for raw_version, of_protocol in of_g.ir.items():
129 jversion = JavaOFVersion(of_protocol.wire_version)
130
131 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700132 if not of_class.name in version_map_per_class:
133 version_map_per_class[of_class.name] = collections.OrderedDict()
134
Andreas Wundsam27303462013-07-16 12:52:35 -0700135 version_map_per_class[of_class.name][jversion] = of_class
136
137 interfaces = []
138 for class_name, version_map in version_map_per_class.items():
139 interfaces.append(JavaOFInterface(class_name, version_map))
140
Andreas Wundsambe168f72013-08-03 22:49:35 -0700141 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
142
Andreas Wundsam27303462013-07-16 12:52:35 -0700143 return interfaces
144
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700145 @memoize
146 def interface_by_name(self, name):
147 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
148
Andreas Wundsam27303462013-07-16 12:52:35 -0700149 @property
150 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700151 def all_classes(self):
152 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
153
154 @property
155 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700156 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700157 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700158
159 for version in self.versions:
160 of_protocol = of_g.ir[version.int_version]
161 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700162 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700163
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700164 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
165 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700166
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700167 # inelegant - need java name here
168 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700169 return enums
170
171 @memoize
172 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700173 res = find(lambda e: e.name == name, self.enums)
174 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700175 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700176 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700177
Andreas Wundsam5204de22013-07-30 11:34:45 -0700178 @property
179 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700180 def of_factories(self):
181 prefix = "org.openflow.protocol"
182
183 factories = OrderedDict()
184
185 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
186 for base_class in sub_factory_classes:
187 package = base_class[2:].lower()
188 remove_prefix = base_class[2].lower() + base_class[3:]
189
190 # HACK need to have a better way to deal with parameterized base classes
191 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
192
193 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
194 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
195
196 factories[""] = OFFactory(
197 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700198 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700199 remove_prefix="",
200 members=[], base_class="OFMessage", sub_factories=OrderedDict(
201 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
202
203 for i in self.interfaces:
204 for n, factory in factories.items():
205 if n == "":
206 factory.members.append(i)
207 break
208 else:
209 super_class = self.interface_by_name(n)
210 if i.is_instance_of(super_class):
211 factory.members.append(i)
212 break
213 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700214
215 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700216 """ return wether or not to generate implementation class clazz.
217 Now true for everything except OFTableModVer10.
218 @param clazz JavaOFClass instance
219 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700220 if clazz.interface.name.startswith("OFMatchV"):
221 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700222 elif clazz.name == "OFTableModVer10":
223 # tablemod ver 10 is a hack and has no oftype defined
224 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700225 if loxi_utils.class_is_message(clazz.interface.c_name):
226 return True
227 if loxi_utils.class_is_oxm(clazz.interface.c_name):
228 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700229 if loxi_utils.class_is_action(clazz.interface.c_name):
230 return True
231 if loxi_utils.class_is_instruction(clazz.interface.c_name):
232 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700233 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700234 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700235
236
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700237class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700238 @property
239 def factory_classes(self):
240 return [ OFFactoryClass(
241 package="org.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700242 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700243 interface=self,
244 version=version
245 ) for version in model.versions ]
246
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700247 def method_name(self, member, builder=True):
248 n = member.variable_name
249 if n.startswith(self.remove_prefix):
250 n = n[len(self.remove_prefix):]
251 n = n[0].lower() + n[1:]
252 if builder:
253 return "build" + n[0].upper() + n[1:]
254 else:
255 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700256
257OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700258class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
259 @property
260 def base_class(self):
261 return self.interface.base_class
262
263 @property
264 def versioned_base_class(self):
265 base_class_interface = model.interface_by_name(self.interface.base_class)
266 if base_class_interface and base_class_interface.has_version(self.version):
267 return base_class_interface.versioned_class(self.version)
268 else:
269 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270
Andreas Wundsam27303462013-07-16 12:52:35 -0700271model = JavaModel()
272
273#######################################################################
274### OFVersion
275#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700276
277class JavaOFVersion(object):
278 """ Models a version of OpenFlow. contains methods to convert the internal
279 Loxi version to a java constant / a string """
280 def __init__(self, int_version):
281 self.int_version = int(int_version)
282
283 @property
284 def of_version(self):
285 return "1" + str(int(self.int_version) - 1)
286
287 @property
288 def constant_version(self):
289 return "OF_" + self.of_version
290
Andreas Wundsam27303462013-07-16 12:52:35 -0700291 def __repr__(self):
292 return "JavaOFVersion(%d)" % self.int_version
293
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700294 def __str__(self):
295 return of_g.param_version_names[self.int_version]
296
Andreas Wundsam27303462013-07-16 12:52:35 -0700297 def __hash__(self):
298 return hash(self.int_version)
299
300 def __eq__(self, other):
301 if other is None or type(self) != type(other):
302 return False
303 return (self.int_version,) == (other.int_version,)
304
305#######################################################################
306### Interface
307#######################################################################
308
309class JavaOFInterface(object):
310 """ Models an OpenFlow Message class for the purpose of the java class.
311 Version agnostic, in contrast to the loxi_ir python model.
312 """
313 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700314 """"
315 @param c_name: loxi style name (e.g., of_flow_add)
316 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
317 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700318 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700319 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700320 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700321 self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700322 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700323 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700324 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700325 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700326 self.constant_name = c_name.upper().replace("OF_", "")
327
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700328 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700329
Andreas Wundsam27303462013-07-16 12:52:35 -0700330 self.package = "org.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.openflow.protocol"
331 if self.name != parent_interface:
332 self.parent_interface = parent_interface
333 else:
334 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700335
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700336 @property
337 @memoize
338 def all_parent_interfaces(self):
339 return [ "OFObject" ] + \
340 ([ self.parent_interface ] if self.parent_interface else [] )+ \
341 self.additional_parent_interfaces
342 @property
343 @memoize
344 def additional_parent_interfaces(self):
345 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
346 m = re.match(r'(.*)Request$', self.name)
347 if m:
348 reply_name = m.group(1) + "Reply"
349 if model.interface_by_name(reply_name):
350 return ["OFRequest<%s>" % reply_name ]
351 return []
352
353
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700354 def is_instance_of(self, other_class):
355 if self == other_class:
356 return True
357 parent = self.super_class
358 if parent is None:
359 return False
360 else:
361 return parent.is_instance_of(other_class)
362
363 @property
364 def super_class(self):
365 if not self.parent_interface:
366 return None
367 else:
368 return model.interface_by_name(self.parent_interface)
369
370
371 def inherited_declaration(self, type_spec="?"):
372 if self.type_annotation:
373 return "%s<%s>" % (self.name, type_spec)
374 else:
375 return "%s" % self.name
376
377 @property
378 def type_variable(self):
379 if self.type_annotation:
380 return "<T>"
381 else:
382 return "";
383
Andreas Wundsam27303462013-07-16 12:52:35 -0700384 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700385 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
386 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
387 # model (note, that the loxi model is on versioned classes). Should check/infer the
388 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700389 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700390 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700391 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700392 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700393 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700394 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700395 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name) and self.name != "OFBsnHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700396 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700397 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name) and self.name != "OFNiciraHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700398 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700399 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
400 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700401 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700402 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700403 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700404 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700405 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 if re.match(r'OFActionBsn.+', self.name):
407 return ("action", "OFActionBsn", None)
408 elif re.match(r'OFActionNicira.+', self.name):
409 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700410 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
411 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700412 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700413 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700414 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700415 return ("", "OFBsnVport", None)
416 elif self.name == "OFOxm":
417 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700418 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700419 if self.name in model.oxm_map:
420 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
421 else:
422 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700423 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700424 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700425 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700426 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700427 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700428 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700429 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700430 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700431 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700432 return ("", None, None)
433
434 @property
435 @memoize
436 def writeable_members(self):
437 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700438
439 @property
440 @memoize
441 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 return self.ir_model_members + self.virtual_members
443
444 @property
445 @memoize
446 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700447 """return a list of all members to be exposed by this interface. Corresponds to
448 the union of the members of the vesioned classes without length, fieldlength
449 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700450 all_versions = []
451 member_map = collections.OrderedDict()
452
453 for (version, of_class) in self.version_map.items():
454 for of_member in of_class.members:
455 if isinstance(of_member, OFLengthMember) or \
456 isinstance(of_member, OFFieldLengthMember) or \
457 isinstance(of_member, OFPadMember):
458 continue
459 if of_member.name not in member_map:
460 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
461
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700462 return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700463
464 @property
465 def virtual_members(self):
466 if self.name == "OFOxm":
467 return (
468 JavaVirtualMember(self, "value", java_type.generic_t),
469 JavaVirtualMember(self, "mask", java_type.generic_t),
470 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
471 JavaVirtualMember(self, "masked", java_type.boolean),
472 )
473 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
474 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
475 if self.name in model.oxm_map \
476 else java_type.make_match_field_jtype()
477
478 return (
479 JavaVirtualMember(self, "matchField", field_type),
480 JavaVirtualMember(self, "masked", java_type.boolean),
481 ) \
482 + \
483 (
484 ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
485 ()
486 )
487 else:
488 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700489
490 @property
491 @memoize
492 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700493 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700494 return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
Andreas Wundsam27303462013-07-16 12:52:35 -0700495
496 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700497 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700498 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700499 return len(self.all_versions) == len(model.versions)
500
501 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700502 @memoize
503 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700504 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700505 return self.version_map.keys()
506
Andreas Wundsam5204de22013-07-30 11:34:45 -0700507 def has_version(self, version):
508 return version in self.version_map
509
Andreas Wundsam27303462013-07-16 12:52:35 -0700510 def versioned_class(self, version):
511 return JavaOFClass(self, version, self.version_map[version])
512
513 @property
514 @memoize
515 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700516 return [ self.versioned_class(version) for version in self.all_versions ]
517
518#######################################################################
519### (Versioned) Classes
520#######################################################################
521
522class JavaOFClass(object):
523 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700524 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700525 """
526 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700527 """
528 @param interface JavaOFInterface instance of the parent interface
529 @param version JavaOFVersion
530 @param ir_class OFClass from loxi_ir
531 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700532 self.interface = interface
533 self.ir_class = ir_class
534 self.c_name = self.ir_class.name
535 self.version = version
536 self.constant_name = self.c_name.upper().replace("OF_", "")
537 self.package = "org.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700538 self.generated = False
539
540 @property
541 @memoize
542 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700543 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700544
545 @property
546 def name(self):
547 return "%sVer%s" % (self.interface.name, self.version.of_version)
548
549 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700550 def variable_name(self):
551 return self.name[3:]
552
553 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700554 def length(self):
555 if self.is_fixed_length:
556 return self.min_length
557 else:
558 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
559
560 @property
561 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700562 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700563 id_tuple = (self.ir_class.name, self.version.int_version)
564 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
565
566 @property
567 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700568 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700569 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
570
571 def all_properties(self):
572 return self.interface.members
573
574 def get_member(self, name):
575 for m in self.members:
576 if m.name == name:
577 return m
578
579 @property
580 @memoize
581 def data_members(self):
582 return [ prop for prop in self.members if prop.is_data ]
583
584 @property
585 @memoize
586 def fixed_value_members(self):
587 return [ prop for prop in self.members if prop.is_fixed_value ]
588
589 @property
590 @memoize
591 def public_members(self):
592 return [ prop for prop in self.members if prop.is_public ]
593
594 @property
595 @memoize
596 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700597 return self.ir_model_members + self.virtual_members
598
599 @property
600 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700602 return tuple(members)
603
604 @property
605 def virtual_members(self):
606 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
607 if self.interface.name in model.oxm_map:
608 oxm_entry = model.oxm_map[self.interface.name]
609 return (
610 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
611 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
612 )
613 else:
614 return (
615 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
616 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
617 )
618 else:
619 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700620
621 def all_versions(self):
622 return [ JavaOFVersion(int_version)
623 for int_version in of_g.unified[self.c_name]
624 if int_version != 'union' and int_version != 'object_id' ]
625
626 def version_is_inherited(self, version):
627 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
628
629 def inherited_from(self, version):
630 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
631
632 @property
633 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700634 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
635
636 @property
637 def discriminator(self):
638 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700639
640 @property
641 def is_extension(self):
642 return type_maps.message_is_extension(self.c_name, -1)
643
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700644 @property
645 def align(self):
646 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
647
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700648 @property
649 @memoize
650 def superclass(self):
651 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
652
653 @property
654 @memoize
655 def subclasses(self):
656 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
657
Andreas Wundsam27303462013-07-16 12:52:35 -0700658#######################################################################
659### Member
660#######################################################################
661
662
663class JavaMember(object):
664 """ Models a property (member) of an openflow class. """
665 def __init__(self, msg, name, java_type, member):
666 self.msg = msg
667 self.name = name
668 self.java_type = java_type
669 self.member = member
670 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700671
672 @property
673 def title_name(self):
674 return self.name[0].upper() + self.name[1:]
675
676 @property
677 def constant_name(self):
678 return self.c_name.upper()
679
680 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700681 def getter_name(self):
682 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
683
684 @property
685 def setter_name(self):
686 return "set" + self.title_name
687
688 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700689 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700690 if self.is_fixed_value:
691 return self.constant_name
692 else:
693 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700694
695 @property
696 def default_value(self):
697 java_type = self.java_type.public_type;
698
Andreas Wundsam27303462013-07-16 12:52:35 -0700699 if self.is_fixed_value:
700 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700701 elif java_type == "OFOxmList":
702 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700703 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700704 return "Collections.emptyList()"
705 elif java_type == "boolean":
706 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700707 elif self.java_type.is_array:
708 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700709 elif java_type in ("byte", "char", "short", "int", "long"):
710 return "({0}) 0".format(java_type);
711 else:
712 return "null";
713
714 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700715 def enum_value(self):
716 if self.name == "version":
717 return "OFVersion.%s" % self.msg.version.constant_version
718
719 java_type = self.java_type.public_type;
720 try:
721 global model
722 enum = model.enum_by_name(java_type)
723 entry = enum.entry_by_version_value(self.msg.version, self.value)
724 return "%s.%s" % ( enum.name, entry.name)
725 except KeyError, e:
726 print e.message
727 return self.value
728
729 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700730 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700731 return isinstance(self.member, OFPadMember)
732
733 def is_type_value(self, version=None):
734 if(version==None):
735 return any(self.is_type_value(version) for version in self.msg.all_versions)
736 try:
737 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
738 except:
739 return False
740
741 @property
742 def is_field_length_value(self):
743 return isinstance(self.member, OFFieldLengthMember)
744
745 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700746 def is_discriminator(self):
747 return isinstance(self.member, OFDiscriminatorMember)
748
749 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700750 def is_length_value(self):
751 return isinstance(self.member, OFLengthMember)
752
753 @property
754 def is_public(self):
755 return not (self.is_pad or self.is_length_value)
756
757 @property
758 def is_data(self):
759 return isinstance(self.member, OFDataMember) and self.name != "version"
760
761 @property
762 def is_fixed_value(self):
763 return hasattr(self.member, "value") or self.name == "version" \
764 or ( self.name == "length" and self.msg.is_fixed_length) \
765 or ( self.name == "len" and self.msg.is_fixed_length)
766
767 @property
768 def value(self):
769 if self.name == "version":
770 return self.msg.version.int_version
771 elif self.name == "length" or self.name == "len":
772 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700773 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700774 return self.java_type.format_value(self.member.value)
775
776 @property
777 def priv_value(self):
778 if self.name == "version":
779 return self.msg.version.int_version
780 elif self.name == "length" or self.name == "len":
781 return self.msg.length
782 else:
783 return self.java_type.format_value(self.member.value, pub_type=False)
784
Andreas Wundsam27303462013-07-16 12:52:35 -0700785
786 @property
787 def is_writeable(self):
788 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
789
790 def get_type_value_info(self, version):
791 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700792
793 @property
794 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700795 if hasattr(self.member, "length"):
796 return self.member.length
797 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700798 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700799 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700800
801 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700802 def for_of_member(java_class, member):
803 if isinstance(member, OFPadMember):
804 return JavaMember(None, "", None, member)
805 else:
806 if member.name == 'len':
807 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700808 elif member.name == 'value_mask':
809 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700810 else:
811 name = java_type.name_c_to_camel(member.name)
812 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
813 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814
815 @property
816 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700817 if not self.msg.c_name in of_g.unified:
818 print("%s not self.unified" % self.msg.c_name)
819 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700820 for version in of_g.unified[self.msg.c_name]:
821 if version == 'union' or version =='object_id':
822 continue
823 if 'use_version' in of_g.unified[self.msg.c_name][version]:
824 continue
825
Andreas Wundsam27303462013-07-16 12:52:35 -0700826 if not self.member.name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700827 return False
828 return True
829
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700830 @property
831 def is_virtual(self):
832 return False
833
Andreas Wundsam27303462013-07-16 12:52:35 -0700834 def __hash__(self):
835 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700836
Andreas Wundsam27303462013-07-16 12:52:35 -0700837 def __eq__(self, other):
838 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700839 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700840 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700841
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700842class JavaVirtualMember(JavaMember):
843 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
844 def __init__(self, msg, name, java_type, value=None):
845 JavaMember.__init__(self, msg, name, java_type, member=None)
846 self._value = value
847
848 @property
849 def is_fixed_value(self):
850 return True
851
852 @property
853 def value(self):
854 return self._value
855
856 @property
857 def priv_value(self):
858 return self._value
859
860
861 @property
862 def is_universal(self):
863 return True
864
865 @property
866 def is_virtual(self):
867 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700868
869#######################################################################
870### Unit Test
871#######################################################################
872
Yotam Harchol466b3212013-08-15 12:14:46 -0700873class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700874 def __init__(self, java_class):
875 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700876 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700877 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700878 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
879 name=java_class.c_name[3:]) + "{i}.data"
880 test_class_name = self.java_class.name + "Test"
881 self.test_units = []
882 if test_data.exists(first_data_file_name):
883 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
884 i = 1
885 while test_data.exists(data_file_template.format(i=i)):
886 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
887 i = i + 1
888
889 @property
890 def package(self):
891 return self.java_class.package
892
893 @property
894 def has_test_data(self):
895 return len(self.test_units) > 0
896
897 @property
898 def length(self):
899 return len(self.test_units)
900
901 def get_test_unit(self, i):
902 return self.test_units[i]
903
904
905class JavaUnitTest(object):
906 def __init__(self, java_class, file_name=None, test_class_name=None):
907 self.java_class = java_class
908 if file_name is None:
909 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
910 name=java_class.c_name[3:])
911 else:
912 self.data_file_name = file_name
913 if test_class_name is None:
914 self.test_class_name = self.java_class.name + "Test"
915 else:
916 self.test_class_name = test_class_name
917
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700918 @property
919 def package(self):
920 return self.java_class.package
921
922 @property
923 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700924 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700925
926 @property
927 def has_test_data(self):
928 return test_data.exists(self.data_file_name)
929
930 @property
931 @memoize
932 def test_data(self):
933 return test_data.read(self.data_file_name)
934
935
Andreas Wundsam27303462013-07-16 12:52:35 -0700936#######################################################################
937### Enums
938#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700939
Andreas Wundsam27303462013-07-16 12:52:35 -0700940class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700941 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700942 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700943
944 if c_name == "of_stats_types":
945 self.name = "OFStatsType"
946 else:
947 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700948
Andreas Wundsam27303462013-07-16 12:52:35 -0700949 # Port_features has constants that start with digits
950 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700951
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700952 self.version_enums = version_enum_map
953
954 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
955 for version, ir_enum in version_enum_map.items():
956 for ir_entry in ir_enum.entries:
957 if "virtual" in ir_entry.params:
958 continue
959 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
960
Andreas Wundsam27303462013-07-16 12:52:35 -0700961 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700962 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700963
964 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700965 self.package = "org.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700966
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700967 def wire_type(self, version):
968 ir_enum = self.version_enums[version]
969 if "wire_type" in ir_enum.params:
970 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
971 else:
972 return java_type.u8
973
974 @property
975 def versions(self):
976 return self.version_enums.keys()
977
Andreas Wundsam27303462013-07-16 12:52:35 -0700978 @memoize
979 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700980 res = find(lambda e: e.name == name, self.entries)
981 if res:
982 return res
983 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700984 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
985
986 @memoize
987 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700988 res = find(lambda e: e.c_name == name, self.entries)
989 if res:
990 return res
991 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700992 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
993
994 @memoize
995 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700996 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
997 if res:
998 return res
999 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001000 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1001
1002# values: Map JavaVersion->Value
1003class JavaEnumEntry(object):
1004 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001005 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001006 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1007 self.values = values
1008
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001009 def has_value(self, version):
1010 return version in self.values
1011
Andreas Wundsam27303462013-07-16 12:52:35 -07001012 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001013 return self.values[version]
1014
1015 def format_value(self, version):
1016 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001017 return res
1018
Andreas Wundsam27303462013-07-16 12:52:35 -07001019 def all_values(self, versions, not_present=None):
1020 return [ self.values[version] if version in self.values else not_present for version in versions ]