blob: 972f05866a6a53a5e03739d5e01ba44d73165ba6 [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),
Yotam Harchola289d552013-09-16 10:10:40 -070081 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070085 "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),
Yotam Harchola289d552013-09-16 10:10:40 -0700103 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700107 "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),
Yotam Harchola289d552013-09-16 10:10:40 -0700111 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
117 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
118 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
119 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
120 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700121 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
122 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700123 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
124 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
125 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
126 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
127 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
128 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
129 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
130 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
131 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700132
Andreas Wundsam27303462013-07-16 12:52:35 -0700133 @property
134 @memoize
135 def versions(self):
136 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
137
138 @property
139 @memoize
140 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700141 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700142
143 for raw_version, of_protocol in of_g.ir.items():
144 jversion = JavaOFVersion(of_protocol.wire_version)
145
146 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700147 if not of_class.name in version_map_per_class:
148 version_map_per_class[of_class.name] = collections.OrderedDict()
149
Andreas Wundsam27303462013-07-16 12:52:35 -0700150 version_map_per_class[of_class.name][jversion] = of_class
151
152 interfaces = []
153 for class_name, version_map in version_map_per_class.items():
154 interfaces.append(JavaOFInterface(class_name, version_map))
155
Andreas Wundsambe168f72013-08-03 22:49:35 -0700156 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
157
Andreas Wundsam27303462013-07-16 12:52:35 -0700158 return interfaces
159
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700160 @memoize
161 def interface_by_name(self, name):
162 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
163
Andreas Wundsam27303462013-07-16 12:52:35 -0700164 @property
165 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700166 def all_classes(self):
167 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
168
169 @property
170 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700171 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700172 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700173
174 for version in self.versions:
175 of_protocol = of_g.ir[version.int_version]
176 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700177 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700178
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700179 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
180 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700181
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700182 # inelegant - need java name here
183 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700184 return enums
185
186 @memoize
187 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700188 res = find(lambda e: e.name == name, self.enums)
189 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700190 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700191 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700192
Andreas Wundsam5204de22013-07-30 11:34:45 -0700193 @property
194 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700195 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700196 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700197
198 factories = OrderedDict()
199
200 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
201 for base_class in sub_factory_classes:
202 package = base_class[2:].lower()
203 remove_prefix = base_class[2].lower() + base_class[3:]
204
205 # HACK need to have a better way to deal with parameterized base classes
206 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
207
208 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
209 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
210
211 factories[""] = OFFactory(
212 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700213 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700214 remove_prefix="",
215 members=[], base_class="OFMessage", sub_factories=OrderedDict(
216 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
217
218 for i in self.interfaces:
219 for n, factory in factories.items():
220 if n == "":
221 factory.members.append(i)
222 break
223 else:
224 super_class = self.interface_by_name(n)
225 if i.is_instance_of(super_class):
226 factory.members.append(i)
227 break
228 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700229
230 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700231 """ return wether or not to generate implementation class clazz.
232 Now true for everything except OFTableModVer10.
233 @param clazz JavaOFClass instance
234 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700235 if clazz.interface.name.startswith("OFMatchV"):
236 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700237 elif clazz.name == "OFTableModVer10":
238 # tablemod ver 10 is a hack and has no oftype defined
239 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700240 if loxi_utils.class_is_message(clazz.interface.c_name):
241 return True
242 if loxi_utils.class_is_oxm(clazz.interface.c_name):
243 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700244 if loxi_utils.class_is_action(clazz.interface.c_name):
245 return True
246 if loxi_utils.class_is_instruction(clazz.interface.c_name):
247 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700248 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700249 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700250
251
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700252class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700253 @property
254 def factory_classes(self):
255 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700256 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700257 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700258 interface=self,
259 version=version
260 ) for version in model.versions ]
261
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700262 def method_name(self, member, builder=True):
263 n = member.variable_name
264 if n.startswith(self.remove_prefix):
265 n = n[len(self.remove_prefix):]
266 n = n[0].lower() + n[1:]
267 if builder:
268 return "build" + n[0].upper() + n[1:]
269 else:
270 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271
272OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700273class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
274 @property
275 def base_class(self):
276 return self.interface.base_class
277
278 @property
279 def versioned_base_class(self):
280 base_class_interface = model.interface_by_name(self.interface.base_class)
281 if base_class_interface and base_class_interface.has_version(self.version):
282 return base_class_interface.versioned_class(self.version)
283 else:
284 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700285
Andreas Wundsam27303462013-07-16 12:52:35 -0700286model = JavaModel()
287
288#######################################################################
289### OFVersion
290#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700291
292class JavaOFVersion(object):
293 """ Models a version of OpenFlow. contains methods to convert the internal
294 Loxi version to a java constant / a string """
295 def __init__(self, int_version):
296 self.int_version = int(int_version)
297
298 @property
299 def of_version(self):
300 return "1" + str(int(self.int_version) - 1)
301
302 @property
303 def constant_version(self):
304 return "OF_" + self.of_version
305
Andreas Wundsam27303462013-07-16 12:52:35 -0700306 def __repr__(self):
307 return "JavaOFVersion(%d)" % self.int_version
308
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700309 def __str__(self):
310 return of_g.param_version_names[self.int_version]
311
Andreas Wundsam27303462013-07-16 12:52:35 -0700312 def __hash__(self):
313 return hash(self.int_version)
314
315 def __eq__(self, other):
316 if other is None or type(self) != type(other):
317 return False
318 return (self.int_version,) == (other.int_version,)
319
320#######################################################################
321### Interface
322#######################################################################
323
324class JavaOFInterface(object):
325 """ Models an OpenFlow Message class for the purpose of the java class.
326 Version agnostic, in contrast to the loxi_ir python model.
327 """
328 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700329 """"
330 @param c_name: loxi style name (e.g., of_flow_add)
331 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
332 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700333 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700334 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700335 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700336 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 -0700337 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700339 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700340 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700341 self.constant_name = c_name.upper().replace("OF_", "")
342
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700343 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700344 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700345 if self.name != parent_interface:
346 self.parent_interface = parent_interface
347 else:
348 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700349
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700350 @property
351 @memoize
352 def all_parent_interfaces(self):
353 return [ "OFObject" ] + \
354 ([ self.parent_interface ] if self.parent_interface else [] )+ \
355 self.additional_parent_interfaces
356 @property
357 @memoize
358 def additional_parent_interfaces(self):
359 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
360 m = re.match(r'(.*)Request$', self.name)
361 if m:
362 reply_name = m.group(1) + "Reply"
363 if model.interface_by_name(reply_name):
364 return ["OFRequest<%s>" % reply_name ]
365 return []
366
367
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700368 def is_instance_of(self, other_class):
369 if self == other_class:
370 return True
371 parent = self.super_class
372 if parent is None:
373 return False
374 else:
375 return parent.is_instance_of(other_class)
376
377 @property
378 def super_class(self):
379 if not self.parent_interface:
380 return None
381 else:
382 return model.interface_by_name(self.parent_interface)
383
384
385 def inherited_declaration(self, type_spec="?"):
386 if self.type_annotation:
387 return "%s<%s>" % (self.name, type_spec)
388 else:
389 return "%s" % self.name
390
391 @property
392 def type_variable(self):
393 if self.type_annotation:
394 return "<T>"
395 else:
396 return "";
397
Andreas Wundsam27303462013-07-16 12:52:35 -0700398 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700399 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
400 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
401 # model (note, that the loxi model is on versioned classes). Should check/infer the
402 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700403 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700404 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700405 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700407 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700408 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700409 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 -0700410 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700411 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 -0700412 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700413 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
414 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700415 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700416 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700417 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700418 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700419 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700420 if re.match(r'OFActionBsn.+', self.name):
421 return ("action", "OFActionBsn", None)
422 elif re.match(r'OFActionNicira.+', self.name):
423 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700424 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
425 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700426 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700427 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700428 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700429 return ("", "OFBsnVport", None)
430 elif self.name == "OFOxm":
431 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700432 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700433 if self.name in model.oxm_map:
434 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
435 else:
436 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700437 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700439 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700440 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700441 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700443 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700444 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700445 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700446 return ("", None, None)
447
448 @property
449 @memoize
450 def writeable_members(self):
451 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700452
453 @property
454 @memoize
455 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700456 return self.ir_model_members + self.virtual_members
457
458 @property
459 @memoize
460 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700461 """return a list of all members to be exposed by this interface. Corresponds to
462 the union of the members of the vesioned classes without length, fieldlength
463 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700464 all_versions = []
465 member_map = collections.OrderedDict()
466
467 for (version, of_class) in self.version_map.items():
468 for of_member in of_class.members:
469 if isinstance(of_member, OFLengthMember) or \
470 isinstance(of_member, OFFieldLengthMember) or \
471 isinstance(of_member, OFPadMember):
472 continue
473 if of_member.name not in member_map:
474 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
475
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700476 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 -0700477
478 @property
479 def virtual_members(self):
480 if self.name == "OFOxm":
481 return (
482 JavaVirtualMember(self, "value", java_type.generic_t),
483 JavaVirtualMember(self, "mask", java_type.generic_t),
484 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
485 JavaVirtualMember(self, "masked", java_type.boolean),
486 )
487 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
488 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
489 if self.name in model.oxm_map \
490 else java_type.make_match_field_jtype()
491
492 return (
493 JavaVirtualMember(self, "matchField", field_type),
494 JavaVirtualMember(self, "masked", java_type.boolean),
495 ) \
496 + \
497 (
498 ( 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
499 ()
500 )
501 else:
502 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700503
504 @property
505 @memoize
506 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700507 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700508 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 -0700509
510 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700511 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700512 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700513 return len(self.all_versions) == len(model.versions)
514
515 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700516 @memoize
517 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700518 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700519 return self.version_map.keys()
520
Andreas Wundsam5204de22013-07-30 11:34:45 -0700521 def has_version(self, version):
522 return version in self.version_map
523
Andreas Wundsam27303462013-07-16 12:52:35 -0700524 def versioned_class(self, version):
525 return JavaOFClass(self, version, self.version_map[version])
526
527 @property
528 @memoize
529 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700530 return [ self.versioned_class(version) for version in self.all_versions ]
531
532#######################################################################
533### (Versioned) Classes
534#######################################################################
535
536class JavaOFClass(object):
537 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700538 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700539 """
540 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700541 """
542 @param interface JavaOFInterface instance of the parent interface
543 @param version JavaOFVersion
544 @param ir_class OFClass from loxi_ir
545 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700546 self.interface = interface
547 self.ir_class = ir_class
548 self.c_name = self.ir_class.name
549 self.version = version
550 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700551 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700552 self.generated = False
553
554 @property
555 @memoize
556 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700557 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700558
559 @property
560 def name(self):
561 return "%sVer%s" % (self.interface.name, self.version.of_version)
562
563 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700564 def variable_name(self):
565 return self.name[3:]
566
567 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 def length(self):
569 if self.is_fixed_length:
570 return self.min_length
571 else:
572 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
573
574 @property
575 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700576 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 id_tuple = (self.ir_class.name, self.version.int_version)
578 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
579
580 @property
581 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700582 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700583 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
584
585 def all_properties(self):
586 return self.interface.members
587
588 def get_member(self, name):
589 for m in self.members:
590 if m.name == name:
591 return m
592
593 @property
594 @memoize
595 def data_members(self):
596 return [ prop for prop in self.members if prop.is_data ]
597
598 @property
599 @memoize
600 def fixed_value_members(self):
601 return [ prop for prop in self.members if prop.is_fixed_value ]
602
603 @property
604 @memoize
605 def public_members(self):
606 return [ prop for prop in self.members if prop.is_public ]
607
608 @property
609 @memoize
610 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700611 return self.ir_model_members + self.virtual_members
612
613 @property
614 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700615 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700616 return tuple(members)
617
618 @property
619 def virtual_members(self):
620 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
621 if self.interface.name in model.oxm_map:
622 oxm_entry = model.oxm_map[self.interface.name]
623 return (
624 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
625 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
626 )
627 else:
628 return (
629 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
630 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
631 )
632 else:
633 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700634
635 def all_versions(self):
636 return [ JavaOFVersion(int_version)
637 for int_version in of_g.unified[self.c_name]
638 if int_version != 'union' and int_version != 'object_id' ]
639
640 def version_is_inherited(self, version):
641 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
642
643 def inherited_from(self, version):
644 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
645
646 @property
647 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700648 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
649
650 @property
651 def discriminator(self):
652 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700653
654 @property
655 def is_extension(self):
656 return type_maps.message_is_extension(self.c_name, -1)
657
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700658 @property
659 def align(self):
660 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
661
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700662 @property
663 @memoize
664 def superclass(self):
665 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
666
667 @property
668 @memoize
669 def subclasses(self):
670 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
671
Andreas Wundsam27303462013-07-16 12:52:35 -0700672#######################################################################
673### Member
674#######################################################################
675
676
677class JavaMember(object):
678 """ Models a property (member) of an openflow class. """
679 def __init__(self, msg, name, java_type, member):
680 self.msg = msg
681 self.name = name
682 self.java_type = java_type
683 self.member = member
684 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700685
686 @property
687 def title_name(self):
688 return self.name[0].upper() + self.name[1:]
689
690 @property
691 def constant_name(self):
692 return self.c_name.upper()
693
694 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700695 def getter_name(self):
696 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
697
698 @property
699 def setter_name(self):
700 return "set" + self.title_name
701
702 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700703 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700704 if self.is_fixed_value:
705 return self.constant_name
706 else:
707 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700708
709 @property
710 def default_value(self):
711 java_type = self.java_type.public_type;
712
Andreas Wundsam27303462013-07-16 12:52:35 -0700713 if self.is_fixed_value:
714 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700715 elif java_type == "OFOxmList":
716 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700717 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700718 return "Collections.emptyList()"
719 elif java_type == "boolean":
720 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700721 elif self.java_type.is_array:
722 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700723 elif java_type in ("byte", "char", "short", "int", "long"):
724 return "({0}) 0".format(java_type);
725 else:
726 return "null";
727
728 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700729 def enum_value(self):
730 if self.name == "version":
731 return "OFVersion.%s" % self.msg.version.constant_version
732
733 java_type = self.java_type.public_type;
734 try:
735 global model
736 enum = model.enum_by_name(java_type)
737 entry = enum.entry_by_version_value(self.msg.version, self.value)
738 return "%s.%s" % ( enum.name, entry.name)
739 except KeyError, e:
740 print e.message
741 return self.value
742
743 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700744 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700745 return isinstance(self.member, OFPadMember)
746
747 def is_type_value(self, version=None):
748 if(version==None):
749 return any(self.is_type_value(version) for version in self.msg.all_versions)
750 try:
751 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
752 except:
753 return False
754
755 @property
756 def is_field_length_value(self):
757 return isinstance(self.member, OFFieldLengthMember)
758
759 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700760 def is_discriminator(self):
761 return isinstance(self.member, OFDiscriminatorMember)
762
763 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700764 def is_length_value(self):
765 return isinstance(self.member, OFLengthMember)
766
767 @property
768 def is_public(self):
769 return not (self.is_pad or self.is_length_value)
770
771 @property
772 def is_data(self):
773 return isinstance(self.member, OFDataMember) and self.name != "version"
774
775 @property
776 def is_fixed_value(self):
777 return hasattr(self.member, "value") or self.name == "version" \
778 or ( self.name == "length" and self.msg.is_fixed_length) \
779 or ( self.name == "len" and self.msg.is_fixed_length)
780
781 @property
782 def value(self):
783 if self.name == "version":
784 return self.msg.version.int_version
785 elif self.name == "length" or self.name == "len":
786 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700787 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700788 return self.java_type.format_value(self.member.value)
789
790 @property
791 def priv_value(self):
792 if self.name == "version":
793 return self.msg.version.int_version
794 elif self.name == "length" or self.name == "len":
795 return self.msg.length
796 else:
797 return self.java_type.format_value(self.member.value, pub_type=False)
798
Andreas Wundsam27303462013-07-16 12:52:35 -0700799
800 @property
801 def is_writeable(self):
802 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
803
804 def get_type_value_info(self, version):
805 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700806
807 @property
808 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700809 if hasattr(self.member, "length"):
810 return self.member.length
811 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700812 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700813 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814
815 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700816 def for_of_member(java_class, member):
817 if isinstance(member, OFPadMember):
818 return JavaMember(None, "", None, member)
819 else:
820 if member.name == 'len':
821 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700822 elif member.name == 'value_mask':
823 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700824 else:
825 name = java_type.name_c_to_camel(member.name)
826 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
827 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700828
829 @property
830 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700831 if not self.msg.c_name in of_g.unified:
832 print("%s not self.unified" % self.msg.c_name)
833 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700834 for version in of_g.unified[self.msg.c_name]:
835 if version == 'union' or version =='object_id':
836 continue
837 if 'use_version' in of_g.unified[self.msg.c_name][version]:
838 continue
839
Andreas Wundsam27303462013-07-16 12:52:35 -0700840 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 -0700841 return False
842 return True
843
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700844 @property
845 def is_virtual(self):
846 return False
847
Andreas Wundsam27303462013-07-16 12:52:35 -0700848 def __hash__(self):
849 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700850
Andreas Wundsam27303462013-07-16 12:52:35 -0700851 def __eq__(self, other):
852 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700853 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700854 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700855
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700856class JavaVirtualMember(JavaMember):
857 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
858 def __init__(self, msg, name, java_type, value=None):
859 JavaMember.__init__(self, msg, name, java_type, member=None)
860 self._value = value
861
862 @property
863 def is_fixed_value(self):
864 return True
865
866 @property
867 def value(self):
868 return self._value
869
870 @property
871 def priv_value(self):
872 return self._value
873
874
875 @property
876 def is_universal(self):
877 return True
878
879 @property
880 def is_virtual(self):
881 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700882
883#######################################################################
884### Unit Test
885#######################################################################
886
Yotam Harchol466b3212013-08-15 12:14:46 -0700887class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700888 def __init__(self, java_class):
889 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700890 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700891 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700892 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
893 name=java_class.c_name[3:]) + "{i}.data"
894 test_class_name = self.java_class.name + "Test"
895 self.test_units = []
896 if test_data.exists(first_data_file_name):
897 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
898 i = 1
899 while test_data.exists(data_file_template.format(i=i)):
900 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
901 i = i + 1
902
903 @property
904 def package(self):
905 return self.java_class.package
906
907 @property
908 def has_test_data(self):
909 return len(self.test_units) > 0
910
911 @property
912 def length(self):
913 return len(self.test_units)
914
915 def get_test_unit(self, i):
916 return self.test_units[i]
917
918
919class JavaUnitTest(object):
920 def __init__(self, java_class, file_name=None, test_class_name=None):
921 self.java_class = java_class
922 if file_name is None:
923 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
924 name=java_class.c_name[3:])
925 else:
926 self.data_file_name = file_name
927 if test_class_name is None:
928 self.test_class_name = self.java_class.name + "Test"
929 else:
930 self.test_class_name = test_class_name
931
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700932 @property
933 def package(self):
934 return self.java_class.package
935
936 @property
937 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700938 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700939
940 @property
941 def has_test_data(self):
942 return test_data.exists(self.data_file_name)
943
944 @property
945 @memoize
946 def test_data(self):
947 return test_data.read(self.data_file_name)
948
949
Andreas Wundsam27303462013-07-16 12:52:35 -0700950#######################################################################
951### Enums
952#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700953
Andreas Wundsam27303462013-07-16 12:52:35 -0700954class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700955 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700956 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700957
958 if c_name == "of_stats_types":
959 self.name = "OFStatsType"
960 else:
961 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700962
Andreas Wundsam27303462013-07-16 12:52:35 -0700963 # Port_features has constants that start with digits
964 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700965
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700966 self.version_enums = version_enum_map
967
968 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
969 for version, ir_enum in version_enum_map.items():
970 for ir_entry in ir_enum.entries:
971 if "virtual" in ir_entry.params:
972 continue
973 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
974
Andreas Wundsam27303462013-07-16 12:52:35 -0700975 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700976 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700977
978 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Yotam Harchol791e4882013-09-05 16:32:56 -0700979 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700980
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700981 def wire_type(self, version):
982 ir_enum = self.version_enums[version]
983 if "wire_type" in ir_enum.params:
984 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
985 else:
986 return java_type.u8
987
988 @property
989 def versions(self):
990 return self.version_enums.keys()
991
Andreas Wundsam27303462013-07-16 12:52:35 -0700992 @memoize
993 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700994 res = find(lambda e: e.name == name, self.entries)
995 if res:
996 return res
997 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700998 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
999
1000 @memoize
1001 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001002 res = find(lambda e: e.c_name == name, self.entries)
1003 if res:
1004 return res
1005 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001006 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1007
1008 @memoize
1009 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001010 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1011 if res:
1012 return res
1013 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001014 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1015
1016# values: Map JavaVersion->Value
1017class JavaEnumEntry(object):
1018 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001019 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001020 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1021 self.values = values
1022
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001023 def has_value(self, version):
1024 return version in self.values
1025
Andreas Wundsam27303462013-07-16 12:52:35 -07001026 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001027 return self.values[version]
1028
1029 def format_value(self, version):
1030 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001031 return res
1032
Andreas Wundsam27303462013-07-16 12:52:35 -07001033 def all_values(self, versions, not_present=None):
1034 return [ self.values[version] if version in self.values else not_present for version in versions ]